c++ - Broken output from libavcodec/swscale, depending on resolution -
i writing video conference software, have h.264 stream decoded libavcoded iyuv , rendered window vmr9 in windowless mode. use directshow graph so.
to avoid unnecessary conversion rgb , (see link), convert iyuv video yuy2 before passing vmr9, libswscale.
i noticed video resolution of 848x480, output video broken, investigated further , came resolutions video broken. exclude libswscale elaboration, added support iyuv+padding iyuv conversion, , worked, resolutions.
still, willing avoid slow iyuv, implemented support nv12 (with libswscale) , yv12 (manually, same iyuv). after doing tests on 2 different computers, came strange results.
resolution yuy2 nv12 iyuv yv12 pc 1 (my laptop) 640x360 ok broken ok broken 848x480 broken broken ok broken 960x540 broken broken ok broken 1024x576 ok ok ok ok 1280x720 ok ok ok broken 1920x1080 ok broken ok broken pc 2 640x360 ok ok ok ok 848x480 ok broken ok broken 960x540 ok ok ok ok 1024x576 ok ok ok ok 1280x720 ok broken ok ok 1920x1080 ok ok ok ok
to exclude vmr9 fault, substituted evr, same results.
i know padding needed memory alignment, , size of padding depends on cpu used (libavcodec doc), may explain difference between 2 computers(first has intel i7-3820qm, second intel core 2 quad q6600). suppose has padding, because images corrupted in way. can see blue t-shirt in lower part of image, , face in upper one.
to follow code conversion. nv12 , yuy2 conversions performed libswscale, while iyuv , yv12 manually.
int pixels = _outputframe->width * _outputframe->height; if (_outputformat == "yuy2") { int stride = _outputframe->width * 2; sws_scale(_convertctx, _outputframe->data, _outputframe->linesize, 0, _outputframe->height, &out, &stride); } else if (_outputformat == "nv12") { int stride[] = { _outputframe->width, _outputframe->width }; uint8_t * dst[] = { out, out + pixels }; sws_scale(_convertctx, _outputframe->data, _outputframe->linesize, 0, _outputframe->height, dst, stride); } else if (_outputformat == "iyuv") { // clean ffmpeg padding (int = 0; < _outputframe->height; i++) // copy y memcpy(out + * _outputframe->width, _outputframe->data[0] + * _outputframe->linesize[0] , _outputframe->width); (int = 0; < _outputframe->height / 2; i++) // copy u memcpy(out + pixels + * _outputframe->width / 2, _outputframe->data[1] + * _outputframe->linesize[1] , _outputframe->width / 2); (int = 0; < _outputframe->height / 2; i++) // copy v memcpy(out + pixels + pixels/4 + * _outputframe->width / 2, _outputframe->data[2] + * _outputframe->linesize[2] , _outputframe->width / 2); } else if (_outputformat == "yv12") { // iyuv, u inverted v plane (int = 0; < _outputframe->height; i++) // copy y memcpy(out + * _outputframe->width, _outputframe->data[0] + * _outputframe->linesize[0], _outputframe->width); (int = 0; < _outputframe->height / 2; i++) // copy v memcpy(out + pixels + * _outputframe->width / 2, _outputframe->data[2] + * _outputframe->linesize[2], _outputframe->width / 2); (int = 0; < _outputframe->height / 2; i++) // copy u memcpy(out + pixels + pixels / 4 + * _outputframe->width / 2, _outputframe->data[1] + * _outputframe->linesize[1], _outputframe->width / 2); }
out
output buffer. _outputframe
libavcodec output avframe. _convertctx
initialized follows.
if (_outputformat == "yuy2") _convertctx = sws_getcontext(_width, _height, av_pix_fmt_yuv420p, _width, _height, av_pix_fmt_yuyv422, sws_fast_bilinear, nullptr, nullptr, nullptr); else if (_outputformat == "nv12") _convertctx = sws_getcontext(_width, _height, av_pix_fmt_yuv420p, _width, _height, av_pix_fmt_nv12, sws_fast_bilinear, nullptr, nullptr, nullptr);
questions:
- are manual conversions correct?
- are assumptions correct?
- is previous 2 answers positive, problem? , especially...
- why presents resolutions , not others?
- what additional info can provide?
Comments
Post a Comment