commit f5986df439c7409c3d866ba3c516558065f8dec9
parent 729e32cb210d5aee6d8459bfbb715efbb706e65d
Author: Andrew Osmond <aosmond@gmail.com>
Date: Thu, 8 Jan 2026 15:56:04 +0000
Bug 2008354 - Part 3. Handle AnnexB output from encoders when AVCC requested. r=media-playback-reviewers,jolin
On Android, the encoders produce AnnexB, so we need to extract the
extradata for the AVCC samples. Since the flag to indicate there was a
configuration change, AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG, is different
from that of a key frame, AMEDIACODEC_BUFFER_FLAG_KEY_FRAME, and we
cannot distinguish when the former happens, we check all frames, not
just the key frames.
This patch also converts the AnnexB frames themselves to AVCC.
Differential Revision: https://phabricator.services.mozilla.com/D277798
Diffstat:
2 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.cpp
@@ -10,6 +10,7 @@
#include <algorithm>
+#include "AnnexB.h"
#include "BufferReader.h"
#include "EncoderConfig.h"
#include "FFmpegEncoderModule.h"
@@ -733,6 +734,20 @@ FFmpegVideoEncoder<LIBAV_VER>::ToMediaRawData(AVPacket* aPacket) {
e.Description().get());
}
+ if (mCodecID == AV_CODEC_ID_H264 &&
+ mConfig.mCodecSpecific.is<H264Specific>() &&
+ mConfig.mCodecSpecific.as<H264Specific>().mFormat ==
+ H264BitStreamFormat::AVC &&
+ !mCodecName.Equals("libx264"_ns) && AnnexB::IsAnnexB(*data)) {
+ if (data->mExtraData) {
+ mLastExtraData = std::move(data->mExtraData);
+ }
+ if (!AnnexB::ConvertSampleToAVCC(data, mLastExtraData)) {
+ return Err(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ "Failed to convert to AVCC"_ns));
+ }
+ }
+
// TODO(bug 1869560): The unit of pts, dts, and duration is time_base, which
// is recommended to be the reciprocal of the frame rate, but we set it to
// microsecond for now.
@@ -773,18 +788,32 @@ FFmpegVideoEncoder<LIBAV_VER>::GetExtraData(AVPacket* aPacket) {
MOZ_ASSERT(mTaskQueue->IsOnCurrentThread());
MOZ_ASSERT(aPacket);
- // H264 Extra data comes with the key frame and we only extract it when
- // encoding into AVCC format.
+ // We only extract the extra data when encoding into AVCC format.
if (mCodecID != AV_CODEC_ID_H264 ||
!mConfig.mCodecSpecific.is<H264Specific>() ||
mConfig.mCodecSpecific.as<H264Specific>().mFormat !=
- H264BitStreamFormat::AVC ||
- !(aPacket->flags & AV_PKT_FLAG_KEY)) {
+ H264BitStreamFormat::AVC) {
return Err(
- MediaResult(NS_ERROR_NOT_AVAILABLE, "No available extra data"_ns));
+ MediaResult(NS_ERROR_NOT_AVAILABLE, "Extra data unnecessary"_ns));
+ }
+
+ Span<const uint8_t> packetBuf(aPacket->data,
+ static_cast<size_t>(aPacket->size));
+ if (!mCodecName.Equals("libx264"_ns) && AnnexB::IsAnnexB(packetBuf)) {
+ auto extraData = AnnexB::ExtractExtraDataForAVCC(packetBuf);
+ if (!extraData) {
+ return Err(MediaResult(NS_ERROR_NOT_AVAILABLE,
+ "Extra data missing from packet"_ns));
+ }
+ return extraData.forget();
}
- if (mCodecName != "libx264") {
+ if (!(aPacket->flags & AV_PKT_FLAG_KEY)) {
+ return Err(MediaResult(NS_ERROR_NOT_AVAILABLE,
+ "Extra data only comes with key frame"_ns));
+ }
+
+ if (!mCodecName.Equals("libx264"_ns)) {
return Err(MediaResult(
NS_ERROR_NOT_IMPLEMENTED,
RESULT_DETAIL(
@@ -805,8 +834,7 @@ FFmpegVideoEncoder<LIBAV_VER>::GetExtraData(AVPacket* aPacket) {
Span<const uint8_t>(mCodecContext->extradata,
static_cast<size_t>(mCodecContext->extradata_size));
} else {
- buf =
- Span<const uint8_t>(aPacket->data, static_cast<size_t>(aPacket->size));
+ buf = packetBuf;
}
if (buf.empty()) {
return Err(MediaResult(NS_ERROR_UNEXPECTED,
diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoEncoder.h
@@ -86,6 +86,7 @@ class FFmpegVideoEncoder<LIBAV_VER> final
int64_t mFakePts = 0;
int64_t mCurrentFramePts = 0;
PtsMap mPtsMap;
+ RefPtr<MediaByteBuffer> mLastExtraData;
};
} // namespace mozilla