3

I have a ​WebM file with one video stream that was encoded with VP9 (libvpx-vp9).

I wrote a C++ program to extract the frames from the video stream and save them out as PNG's. This works fine except that the resulting PNG's are missing alpha.

If I extract the frames from the same WebM file using FFMPEG the resulting PNG's do contain alpha. Here is the output from FFMPEG:

$ ffmpeg -c:v libvpx-vp9 -i temp/anim.webm temp/output-%3d.png

[libvpx-vp9 @ 0000024732b106c0] v1.10.0-rc1-11-gcb0d8ce31
    Last message repeated 1 times
Input #0, matroska,webm, from 'temp/anim.webm':
  Metadata:
    ENCODER         : Lavf58.45.100
  Duration: 00:00:04.04, start: 0.000000, bitrate: 112 kb/s
  Stream #0:0: Video: vp9 (Profile 0), yuva420p(tv), 640x480, SAR 1:1 DAR 4:3, 25 fps, 25 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      alpha_mode      : 1
      ENCODER         : Lavc58.91.100 libvpx-vp9
      DURATION        : 00:00:04.040000000

FFMPEG identifies the stream format as yuva420p.

Here is the output from my program when av_dump_format is called:

Input #0, matroska,webm, from 'temp/anim.webm':
  Metadata:
    ENCODER         : Lavf58.45.100
  Duration: 00:00:04.04, start: 0.000000, bitrate: 112 kb/s
  Stream #0:0: Video: vp9 (Profile 0), yuv420p(tv), 640x480, SAR 1:1 DAR 4:3, 25 fps, 25 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      alpha_mode      : 1
      ENCODER         : Lavc58.91.100 libvpx-vp9
      DURATION        : 00:00:04.040000000

Notice that the detected stream format is yuv420p (the alpha is missing).

Does anybody know how to force the stream format to use alpha?

My setup code resembles the following (error handling is omitted)

auto result = avformat_open_input(&formatContext, fileName.c_str(), nullptr, nullptr);
auto result = avformat_find_stream_info(formatContext, nullptr);
streamIndex = av_find_best_stream(formatContext, mediaType, -1, -1, nullptr, 0);
auto stream = formatContext->streams[streamIndex];
const auto codecIdentifier{ AV_CODEC_ID_VP9 };
auto decoder = avcodec_find_decoder(codecIdentifier);
pCodecContext = avcodec_alloc_context3(decoder);
auto result = avcodec_open2(pCodecContext, decoder, &options);
// AV_PIX_FMT_YUV420P - missing alpha
auto pixelFormat = pCodecContext->pix_fmt;

Gyan pointed out what the problem was. Here is the corrected code:

In case anybody else runs into this issue in the future here is the code (error handling omitted):

auto formatContext = avformat_alloc_context();
formatContext->video_codec_id = AV_CODEC_ID_VP9;
const auto decoder = avcodec_find_decoder_by_name("libvpx-vp9");
formatContext->video_codec = decoder;
avformat_open_input(&formatContext, fileName.c_str(), nullptr, nullptr);
avformat_find_stream_info(formatContext.get(), nullptr);
for (unsigned int streamIndex = 0; streamIndex < formatContext->nb_streams; ++streamIndex) {
    // Displayed the stream format as yuva420p (contains alpha)
    av_dump_format(formatContext, static_cast<int>(streamIndex), fileName.toStdString().c_str(), 0);
}
```

Thanks,
David
  • 31
  • 3

1 Answers1

4

Like your ffmpeg command, you have to force the vpx decoder.

Use

auto decoder = avcodec_find_decoder_by_name("libvpx-vp9");
Gyan
  • 85,394
  • 9
  • 169
  • 201
  • Thanks for your suggestion. I tried that but unfortunately the AVCodecContext pix_fmt is still missing the alpha component (still AV_PIX_FMT_YUV420P). – David Mar 21 '21 at 22:23
  • Assign the video codec in the format context before opening format and find_stream_info – Gyan Mar 22 '21 at 04:55
  • Yes - that fixed my issue! Thanks again. Much appreciated. – David Mar 24 '21 at 01:44
  • Is it still required to do 'avcodec_find_decoder_by_name("libvpx-vp9");', or does assigning the video codec before opening format work on its own? I get an error that there is no codec with that name. But decoding vp9 works. – avl_sweden Mar 07 '23 at 07:44
  • Yes, the default decoder is the native one, which doesn't decode alpha. You likely don't have libvpx linked. – Gyan Mar 07 '23 at 11:24