2016-08-15 4 views
0

Я ищу быстрый способ добавления собственного альфа-канала в декодированный кадр ffmpeg.Запись альфа-канала в декодированный кадр ffmpeg

У меня есть AVI-файл с информацией RGB, и у меня есть синхронизированный видеопоток, описывающий альфа-канал прозрачности (оттенки серого). При декодировании файла AVI с помощью ffmpeg я хочу преобразовать выходной кадр в RGBA, добавив свою собственную альфа-информацию. В конце концов, я получу полупрозрачный видеопоток.

Есть ли оптимизированная функция, возможно, в libswscale или libswresample, чтобы сделать такую ​​вещь лучше, чем просто перебирать пиксели?

В основном я хотел бы иметь возможность написать такую ​​функцию, если бы у меня была такая функция, как sws_scale_and_add_alpha:

void* FFmpegLib_nextFrame_withAlpha(void* _handle, uint8_t* my_alpha_channel) 
{ 
    FFmpegLibHandle* handle = (FFmpegLibHandle*)_handle; 
    AVPacket  packet; 
    int    frameFinished; 

    while(av_read_frame(handle->pFormatCtx, &packet) >= 0) { 
     // Is this a packet from the video stream? 
     if(packet.stream_index==handle->videoStream) { 
      // Decode video frame 
      avcodec_decode_video2(handle->pCodecCtx, handle->pFrame, &frameFinished, &packet); 
      // Did we get a video frame? 
      if(frameFinished) { 
       sws_scale_and_add_alpha 
       (
        handle->sws_ctx, 
        (uint8_t const * const *)handle->pFrame->data, 
        handle->pFrame->linesize, 
        0, 
        handle->pCodecCtx->height, 
        handle->pFrameARGB->data, 
        handle->pFrameARGB->linesize, 
        my_alpha_channel 
       ); 

       return handle->pFrameARGB->data; 
      } 
     } 
    } 

    return NULL; 
} 

ответ

1

Я думал о два способа сделать это. Обычно, если я хочу объединить альфа-канал в командной строке, ffmpeg предоставляет для этого фильтр alphamerge. И я уверен, что вы можете сделать то же самое в C, хотя это может быть сложно запрограммировать (даже в примере ffmpeg есть пример видеофильма).

Второй - это просто его кодирование, против структуры AVFrame. Поле data AVFrame содержит информацию о пикселях. Нам нужно упаковать в него наш альфа-канал.

сначала преобразовать сжатое изображение кадра в упакованном ARGB как обычно

// pFrameARGB should have been allocated and of pix_fmt `AV_PIX_FMT_ARGB` 
sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, height, pFrameARGB->data, pFrameARGB->linesize); 

AVFrame.data является мульти-размер массива содержат различные плоскости. Здесь у нас есть упакованное изображение ARGB, а не плоское, так что data[0] содержит все пиксели, которые нам нужны.

// cpp example, easy to convert to pure C 
auto p = pFrameARGB->data[0]; 
for (auto i = 0; i < width * height; i++) { 
    auto num = i * sizeof(uint8_t) * 4; 
    auto div_result = std::div(num, width * sizeof(uint8_t) * 4); 

    auto offset = pFrameARGB->linesize * div_result.quot + div_result.rem; 
    p[offset] = my_alpha_channel[i]; 
} 
+0

Thanks @halfelf. Я видел пример альфа-карты и даже прокрался в реализацию c. Это немного похоже на ваш второй вариант программирования, поскольку он проходит через пиксели изображения argb. Я надеялся, по соображениям производительности, сделать это одним выстрелом, например, использовать замену sws_scale, которая будет конвертировать и добавлять альфа-канал одновременно. На самом деле, в конце концов, я использую rgb и альфа-каналы в качестве текстуры для шейдера OpenGL, поэтому он выглядит как лучший и самый параллельный вариант - объединить цвет и прозрачность внутри шейдера. –

+0

@ Mic Приятно это слышать. На самом деле я уже делал подобные вещи в CUDA. Я считаю, что его производительность не хуже OpenGL. – halfelf