The data read by VideoReader is inconsistent between Ubuntu and Windows 10.

5 views (last 30 days)
Using VideoReader to read the same video file on Ubuntu 24.04.1 and Windows 10 produces different data results.
On Ubuntu, MATLAB '24.1.0.2689473 (R2024a) Update 6' is used. The following code is executed for reading:
V=VideoReader('~/matlab_test/videoreader/6M7A1148.MOV');
F=read(V,1);
F([1 2 3 4 5])
The output result is:
21 21 21 21 22
Using MATLAB '9.12.0.2529717 (R2022a) Update 8' on Windows, execute the following code:
V=VideoReader('6M7A1148.MOV');
F=read(V,1);
F([1 2 3 4 5])
The output result is:
23 23 23 23 24
I compared the two files on Ubuntu and Windows, and their MD5 checksums are completely identical.
What is causing this inconsistency? How can it be resolved?
The video can be found in the link below.
  1 Comment
Walter Roberson
Walter Roberson on 31 Mar 2025
When I test on my Intel iMac back to R2015aSP1, the result is 36 36 36 36 37 for every version except R2015aSP1 (which gives a message about not being able to initialize internal resources.)

Sign in to comment.

Accepted Answer

敬 杨
敬 杨 on 3 Apr 2025
As Hitesh mentioned, this issue is indeed caused by VideoReader using different third-party libraries on different operating systems.
My goal is to unify the function's behavior across these operating systems. With the help of DeepSeek and ChatGPT, I used C language and the FFmpeg library to solve this problem.
Save the following code as ff.c file.
#include "mex.h"
#include "matrix.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
void extract_frame(const char *filename, int frame_number, int *width, int *height, uint8_t **outputBuffer) {
AVFormatContext *pFormatCtx = NULL;
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
mexErrMsgTxt("Unable to open video file");
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("Unable to get stream information");
}
int videoStream = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
}
if (videoStream == -1) {
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("No video stream found");
}
AVCodecParameters *pCodecPar = pFormatCtx->streams[videoStream]->codecpar;
const AVCodec *pCodec = avcodec_find_decoder(pCodecPar->codec_id);
if (!pCodec) {
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("No decoder found");
}
AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx) {
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("Unable to create decode context");
}
if (avcodec_parameters_to_context(pCodecCtx, pCodecPar) < 0) {
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("Unable to copy codec parameters");
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
mexErrMsgTxt("Unable to open the decoder");
}
AVFrame *pFrame = av_frame_alloc();
AVFrame *pFrameRGB = av_frame_alloc();
struct SwsContext *sws_ctx = NULL;
AVPacket packet;
int frame_count = 0;
int got_frame = 0;
*outputBuffer = NULL;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoStream) {
if (avcodec_send_packet(pCodecCtx, &packet) < 0) {
av_packet_unref(&packet);
continue;
}
while (avcodec_receive_frame(pCodecCtx, pFrame) >= 0) {
frame_count++;
if (frame_count == frame_number) {
// RGB
const enum AVPixelFormat dst_format = AV_PIX_FMT_RGB24;
sws_ctx = sws_getCachedContext(sws_ctx,
pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, dst_format,
SWS_BILINEAR, NULL, NULL, NULL);
*width = pCodecCtx->width;
*height = pCodecCtx->height;
// BUFFER
int buffer_size = av_image_get_buffer_size(dst_format, *width, *height, 1);
*outputBuffer = (uint8_t*)av_malloc(buffer_size);
// FILL
av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize,
*outputBuffer, dst_format, *width, *height, 1);
// format conversion
sws_scale(sws_ctx, (const uint8_t* const*)pFrame->data,
pFrame->linesize, 0, pFrame->height,
pFrameRGB->data, pFrameRGB->linesize);
av_frame_unref(pFrame);
av_packet_unref(&packet);
goto cleanup;
}
av_frame_unref(pFrame);
}
}
av_packet_unref(&packet);
}
cleanup:
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
sws_freeContext(sws_ctx);
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nrhs != 2) {
mexErrMsgTxt("frame = extract_frame_mex(filename, frame_number)");
}
char filename[512];
mxGetString(prhs[0], filename, sizeof(filename));
int frame_number = (int)mxGetScalar(prhs[1]);
int width, height;
uint8_t *frame_data = NULL;
extract_frame(filename, frame_number, &width, &height, &frame_data);
if (!frame_data) {
mexErrMsgTxt("Description Failed to extract the video frame");
}
const mwSize dims[3] = {width,height,3};
plhs[0] = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL);
// memcpy(mxGetData(plhs[0]), frame_data, width * height * 3);
uint8_t *matlab_data = (uint8_t*)mxGetData(plhs[0]);
// printf("%d %d %d %d %d\n",frame_data[0],frame_data[1],frame_data[2],frame_data[3],frame_data[4]);
const int plane_size = width * height;
#pragma omp parallel for collapse(2)
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width;++x) {
const size_t idx = y + x * height;
matlab_data[idx] = frame_data[idx*3]; // r
matlab_data[idx + plane_size] = frame_data[idx*3 + 1]; // g
matlab_data[idx + 2 * plane_size] = frame_data[idx*3 + 2]; // b
}
}
const mwSize dims2[3] = {height,width, 3};
plhs[0] = mxCreateNumericArray(3, dims2, mxUINT8_CLASS, mxREAL);
uint8_t *matlab_data2 = (uint8_t*)mxGetData(plhs[0]);
#pragma omp parallel for collapse(2)
for(int i = 0;i<height;++i)
{
for(int j=0;j<width;++j)
{
int idx_old = j + i*width;
int idx_new = i + j*height;
// printf("%d %d\n",idx_old,idx_new);
matlab_data2 [idx_new] = matlab_data[idx_old];
matlab_data2 [idx_new+plane_size] = matlab_data[idx_old+plane_size];
matlab_data2 [idx_new+ 2 * plane_size] = matlab_data[idx_old+ 2 * plane_size];
// printf("%d %d\n",matlab_data[idx_old],matlab_data2 [idx_new] );
// printf("-----------------------\n");
}
}
av_free(frame_data);
}
And then execute:
mex ff4.c -IC:\ffmpeg-master-latest-win64-gpl-shared\include ...
-LC:\ffmpeg-master-latest-win64-gpl-shared\lib ...
-lavformat -lavcodec -lavutil -lswscale -lswresample
Then, call the function using the following format:
A1= ff4('6M7A1148.MOV', 1);
The first parameter is the video file path, and the second parameter specifies the frame number.
When compiling with mex, ensure that the FFmpeg library is available and that your system variables include the corresponding header files.

More Answers (1)

Hitesh
Hitesh on 3 Apr 2025
Hi 敬 杨,
The variation in frame values across different operating systems is due to the platform-specific third-party libraries used for video reading. Each OS utilizes its built-in media library, which results in these differences.
For a more comprehensive understanding of the video formats supported by each platform, kindly refer to the following MATLAB documentation:

Products


Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!