#ffmpeg #cairo #yuv #libav #swscale
#ffmpeg #Каир #юв #либав #swscale
Вопрос:
Мне нужно закодировать серию кадров из CAIRO_FORMAT_ARGB32 в AV_PIX_FMT_YUV420P с помощью sws_scale. Из документов ffmpeg я узнал, что AV-эквивалент исходного формата-AV_PIX_FMT_ARGB, поэтому вот мой код:
// Set up conversion context img-gt;sws_ctx = sws_getCachedContext( img-gt;sws_ctx, img-gt;video_size[0], img-gt;video_size[1], AV_PIX_FMT_ARGB, img-gt;video_size[0], img-gt;video_size[1], AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL); width = cairo_image_surface_get_width( surface ); height = cairo_image_surface_get_height( surface ); stride = cairo_image_surface_get_stride( surface ); pix = cairo_image_surface_get_data( surface ); const int in_linesize[1] = { stride }; sws_scale( img-gt;sws_ctx, (const uint8_t * const *) amp;pix, in_linesize, 0, img-gt;video_size[1], img-gt;video_frame-gt;data, img-gt;video_frame-gt;linesize); img-gt;video_frame-gt;pts ;
К сожалению, видео не воспроизводится, и VLC показывает кучу этих бесполезных сообщений:
[h264 @ 0x7f6ce0cbc1c0] mmco: unref short failure [h264 @ 0x7f6ce0c39a80] co located POCs unavailable [h264 @ 0x7f6ce0c82800] co located POCs unavailable [h264 @ 0x7f6ce0c9f400] mmco: unref short failure
Процесс кодирования работает просто отлично. Я также попытался использовать const int in_linesize[1] = { 3 * ширина }; Где я ошибаюсь?
Ответ №1:
В следующем ответе показано, как использовать sws_scale для преобразования ARGB в YUV420p.
Вы должны внести некоторые изменения для интеграции преобразования в свой код.
Пример кода — «автономный» пример sws_scale, в котором не используется CAIRO.
Создайте образец ввода BGRA с помощью FFmpeg (инструмент командной строки):
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt argb -frames 1 -f rawvideo argb_image.bin
В следующем примере кода применяются следующие этапы:
- Считайте входные данные ARGB (образец) из двоичного файла.
- Выделите буферы памяти для хранения выходных данных YUV420p.
- Получите контекст SWS.
- Примените преобразование цвета.
- Запишите выходное изображение YUV420p в двоичный файл (для тестирования).
- Свободная выделенная память.
Пример кода на C :
#include lt;stdio.hgt; #include lt;string.hgt; #include lt;stdint.hgt; extern "C" { #include lt;libswscale/swscale.hgt; #include lt;libavutil/imgutils.hgt; } int main() { //Use FFmpeg for building raw ARGB image (used as input). //ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt argb -frames 1 -f rawvideo argb_image.bin const int width = 192; const int height = 108; unsigned char* argb_in = new uint8_t[width * height * 4]; //Allocate 4 bytes per pixel (applies ARGB) const enum AVPixelFormat out_pix_fmt = AV_PIX_FMT_YUV420P; //Read input image for binary file (for testing) //////////////////////////////////////////////////////////////////////////// FILE* f = fopen("argb_image.bin", "rb"); //For using fopen in Visual Studio, define: _CRT_SECURE_NO_WARNINGS (or use fopen_s). fread(argb_in, 1, width * height * 4, f); fclose(f); //////////////////////////////////////////////////////////////////////////// //Allocate output buffers: //////////////////////////////////////////////////////////////////////////// // YUV420p data is separated in three planes // 1. Y - intensity plane, resolution: width x height // 2. U - Color plane, resolution: width/2 x height/2 // 3. V - Color plane, resolution: width/2 x height/2 int out_linesize[4] = {0, 0, 0, 0}; uint8_t* out_planes[4] = { nullptr, nullptr, nullptr, nullptr }; int sts = av_image_alloc(out_planes, //uint8_t * pointers[4], out_linesize, //int linesizes[4], width, //int w, height, //int h, out_pix_fmt, //enum AVPixelFormat pix_fmt, 32); //int align); //Align to 32 bytes address may result faster execution time compared to 1 byte aligenment. if (sts lt; 0) { printf("Error: av_image_alloc response = %dn", sts); return -1; } //////////////////////////////////////////////////////////////////////////// //Get SWS context //////////////////////////////////////////////////////////////////////////// struct SwsContext* sws_context = nullptr; sws_context = sws_getCachedContext(sws_context, //struct SwsContext *context, width, //int srcW, height, //int srcH, AV_PIX_FMT_ARGB, //enum AVPixelFormat srcFormat, width, //int dstW, height, //int dstH, out_pix_fmt, //enum AVPixelFormat dstFormat, SWS_BILINEAR, //int flags, nullptr, //SwsFilter *srcFilter, nullptr, //SwsFilter *dstFilter, nullptr); //const double *param); if (sws_context == nullptr) { printf("Error: sws_getCachedContext returned nullptrn"); return -1; } //////////////////////////////////////////////////////////////////////////// //Apply color conversion //////////////////////////////////////////////////////////////////////////// const int in_linesize[1] = { 4 * width }; // ARGB stride (4 bytes per pixel - assume data is continuous). const uint8_t* in_planes[1] = { argb_in }; int response = sws_scale(sws_context, //struct SwsContext *c, in_planes, //const uint8_t *const srcSlice[], in_linesize, //const int srcStride[], 0, //int srcSliceY, height, //int srcSliceH, out_planes, //uint8_t *const dst[], out_linesize); //const int dstStride[]); if (response lt; 0) { printf("Error: sws_scale response = %dn", response); return -1; } //////////////////////////////////////////////////////////////////////////// //Write YUV420p output image to binary file (for testing) //You may execute FFmpeg after conversion for testing the output: //ffmpeg -y -f rawvideo -s 192x108 -pixel_format yuv420p -i yuv420p_image.bin rgb.png //////////////////////////////////////////////////////////////////////////// f = fopen("yuv420p_image.bin", "wb"); fwrite(out_planes[0], 1, width * height, f); fwrite(out_planes[1], 1, width * height / 4, f); fwrite(out_planes[2], 1, width * height / 4, f); fclose(f); //////////////////////////////////////////////////////////////////////////// //Free allocated memory //////////////////////////////////////////////////////////////////////////// av_freep(out_planes); sws_freeContext(sws_context); delete[] argb_in; //////////////////////////////////////////////////////////////////////////// return 0; }
Для тестирования вывода преобразуйте yuv420p_image.bin
изображение в формат PNG с помощью FFmpeg:
ffmpeg -y -f rawvideo -s 192x108 -pixel_format yuv420p -i yuv420p_image.bin rgb.png
Комментарии:
1. Большое спасибо за время, которое вы потратили на написание этого ответа, я очень признателен, но, к сожалению, это не помогает. Я использовал sws_scale и проверил его возвращаемое значение, никаких ошибок во время кодирования, но видео показывает только первое изображение с неправильными цветами, а затем останавливается, и VLC показывает кучу ошибок, таких как следующие: [h264 @ 0x7f8410cd9400] mmco: короткий сбой [h264 @ 0x7f8410c82c00] co, расположенный POCs недоступен [h264 @ 0x7f8410c9f980] co, расположенный POCs недоступен Хотели бы вы помочь? Это проект GTK 3, который я разрабатываю с 2009 года, графический интерфейс чистый и аккуратный, просто, к сожалению, его недооценивают.