sws_scale генерирует искаженное видео

#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  

rgb.png (результат преобразования FFmpeg):
введите описание изображения здесь

Комментарии:

1. Большое спасибо за время, которое вы потратили на написание этого ответа, я очень признателен, но, к сожалению, это не помогает. Я использовал sws_scale и проверил его возвращаемое значение, никаких ошибок во время кодирования, но видео показывает только первое изображение с неправильными цветами, а затем останавливается, и VLC показывает кучу ошибок, таких как следующие: [h264 @ 0x7f8410cd9400] mmco: короткий сбой [h264 @ 0x7f8410c82c00] co, расположенный POCs недоступен [h264 @ 0x7f8410c9f980] co, расположенный POCs недоступен Хотели бы вы помочь? Это проект GTK 3, который я разрабатываю с 2009 года, графический интерфейс чистый и аккуратный, просто, к сожалению, его недооценивают.