summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorservolk <servolk@chromium.org>2015-08-17 22:20:23 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-18 05:21:09 +0000
commitb199d3440e7b516c98cae679e779af9f5670ef44 (patch)
tree1266a171077201b32562f048c2023ab31e1455ff /media
parent6e682fb12c0c1287836ecf58d293448b940d4689 (diff)
downloadchromium_src-b199d3440e7b516c98cae679e779af9f5670ef44.zip
chromium_src-b199d3440e7b516c98cae679e779af9f5670ef44.tar.gz
chromium_src-b199d3440e7b516c98cae679e779af9f5670ef44.tar.bz2
Refactor AnnexB bitstream conversion for AVC/H.264
Having an explicit bitstream converter interface will allow us to move AnnexB conversion code (PrepareAVCBuffer) from mp4_stream_parser.cc into avc.cc, resulting in cleaner separation of generic mp4 parser code and codec-specific parts. Which has two advantages: 1. It will simplify HEVC integration by removing HEVC specific code from public interfaces and might eventually allow us to toggle HEVC with a local gyp/gn flag and get rid of the global define that has caused a lot of contention in the current version of HEVC CL. 2. After some additional work we should be able to unify AnnexB bitstream conversion code, which is currently duplicated between MSE and FFmpeg code paths (see crbug.com/455379). BUG=455379 Review URL: https://codereview.chromium.org/1289923003 Cr-Commit-Position: refs/heads/master@{#343818}
Diffstat (limited to 'media')
-rw-r--r--media/BUILD.gn2
-rw-r--r--media/formats/mp4/avc.cc33
-rw-r--r--media/formats/mp4/avc.h20
-rw-r--r--media/formats/mp4/bitstream_converter.cc14
-rw-r--r--media/formats/mp4/bitstream_converter.h46
-rw-r--r--media/formats/mp4/box_definitions.cc9
-rw-r--r--media/formats/mp4/box_definitions.h5
-rw-r--r--media/formats/mp4/mp4_stream_parser.cc28
-rw-r--r--media/formats/mp4/mp4_stream_parser.h3
-rw-r--r--media/media.gyp2
10 files changed, 129 insertions, 33 deletions
diff --git a/media/BUILD.gn b/media/BUILD.gn
index af3028d..02d8b04 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -460,6 +460,8 @@ component("media") {
"formats/mp4/aac.h",
"formats/mp4/avc.cc",
"formats/mp4/avc.h",
+ "formats/mp4/bitstream_converter.cc",
+ "formats/mp4/bitstream_converter.h",
"formats/mp4/box_definitions.cc",
"formats/mp4/box_definitions.h",
"formats/mp4/box_reader.cc",
diff --git a/media/formats/mp4/avc.cc b/media/formats/mp4/avc.cc
index 7b8ace2..7451a5f 100644
--- a/media/formats/mp4/avc.cc
+++ b/media/formats/mp4/avc.cc
@@ -307,5 +307,38 @@ bool AVC::IsValidAnnexB(const uint8* buffer, size_t size,
return order_state >= kAfterFirstVCL;
}
+
+AVCBitstreamConverter::AVCBitstreamConverter(
+ scoped_ptr<AVCDecoderConfigurationRecord> avc_config)
+ : avc_config_(avc_config.Pass()) {
+ DCHECK(avc_config_);
+}
+
+AVCBitstreamConverter::~AVCBitstreamConverter() {
+}
+
+bool AVCBitstreamConverter::ConvertFrame(
+ std::vector<uint8>* frame_buf,
+ bool is_keyframe,
+ std::vector<SubsampleEntry>* subsamples) const {
+ // Convert the AVC NALU length fields to Annex B headers, as expected by
+ // decoding libraries. Since this may enlarge the size of the buffer, we also
+ // update the clear byte count for each subsample if encryption is used to
+ // account for the difference in size between the length prefix and Annex B
+ // start code.
+ RCHECK(AVC::ConvertFrameToAnnexB(avc_config_->length_size, frame_buf,
+ subsamples));
+
+ if (is_keyframe) {
+ // If this is a keyframe, we (re-)inject SPS and PPS headers at the start of
+ // a frame. If subsample info is present, we also update the clear byte
+ // count for that first subsample.
+ RCHECK(AVC::InsertParamSetsAnnexB(*avc_config_, frame_buf, subsamples));
+ }
+
+ DCHECK(AVC::IsValidAnnexB(*frame_buf, *subsamples));
+ return true;
+}
+
} // namespace mp4
} // namespace media
diff --git a/media/formats/mp4/avc.h b/media/formats/mp4/avc.h
index add88bb..a774ddd 100644
--- a/media/formats/mp4/avc.h
+++ b/media/formats/mp4/avc.h
@@ -8,7 +8,9 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "media/base/media_export.h"
+#include "media/formats/mp4/bitstream_converter.h"
namespace media {
@@ -57,6 +59,24 @@ class MEDIA_EXPORT AVC {
const uint8* ptr);
};
+// AVCBitstreamConverter converts AVC/H.264 bitstream from MP4 container format
+// with embedded NALU lengths into AnnexB bitstream format (described in ISO/IEC
+// 14496-10) with 4-byte start codes. It also knows how to handle CENC-encrypted
+// streams and adjusts subsample data for those streams while converting.
+class AVCBitstreamConverter : public BitstreamConverter {
+ public:
+ explicit AVCBitstreamConverter(
+ scoped_ptr<AVCDecoderConfigurationRecord> avc_config);
+
+ // BitstreamConverter interface
+ bool ConvertFrame(std::vector<uint8>* frame_buf,
+ bool is_keyframe,
+ std::vector<SubsampleEntry>* subsamples) const override;
+ private:
+ ~AVCBitstreamConverter() override;
+ scoped_ptr<AVCDecoderConfigurationRecord> avc_config_;
+};
+
} // namespace mp4
} // namespace media
diff --git a/media/formats/mp4/bitstream_converter.cc b/media/formats/mp4/bitstream_converter.cc
new file mode 100644
index 0000000..fc972cb
--- /dev/null
+++ b/media/formats/mp4/bitstream_converter.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/formats/mp4/bitstream_converter.h"
+
+namespace media {
+namespace mp4 {
+
+BitstreamConverter::~BitstreamConverter() {
+}
+
+} // namespace mp4
+} // namespace media
diff --git a/media/formats/mp4/bitstream_converter.h b/media/formats/mp4/bitstream_converter.h
new file mode 100644
index 0000000..b5dfdf1
--- /dev/null
+++ b/media/formats/mp4/bitstream_converter.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FORMATS_MP4_BITSTREAM_CONVERTER_H_
+#define MEDIA_FORMATS_MP4_BITSTREAM_CONVERTER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+
+namespace media {
+
+struct SubsampleEntry;
+
+namespace mp4 {
+
+// BitstreamConverter provides a unified interface for performing some common
+// bitstream conversions (e.g. H.264 MP4 bitstream to Annex B, and elementary
+// AAC stream to ADTS).
+class BitstreamConverter
+ : public base::RefCountedThreadSafe<BitstreamConverter> {
+ public:
+ // Converts a single frame/buffer |frame_buf| into the output format.
+ // Returns true iff the conversion was successful.
+ // |frame_buf| is an input/output parameter, it contains input frame data and
+ // contains converted output data if conversion was successful.
+ // |is_keyframe| indicates whether it's a key frame or not.
+ // |subsamples| is an input/output parameter that contains CENC subsample
+ // information. The conversion code should |subsamples| to determine if parts
+ // of input frame are encrypted and should update |subsamples| if necessary,
+ // to make sure it correctly describes the converted output frame. See
+ // SubsampleEntry definition in media/base/decrypt_config.h for more info.
+ virtual bool ConvertFrame(std::vector<uint8>* frame_buf,
+ bool is_keyframe,
+ std::vector<SubsampleEntry>* subsamples) const = 0;
+ protected:
+ friend class base::RefCountedThreadSafe<BitstreamConverter>;
+ virtual ~BitstreamConverter();
+};
+
+} // namespace mp4
+} // namespace media
+
+#endif // MEDIA_FORMATS_MP4_AVC_H_
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 1d758a9..8c6728d 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -518,8 +518,13 @@ bool VideoSampleEntry::Parse(BoxReader* reader) {
}
}
- if (IsFormatValid())
- RCHECK(reader->ReadChild(&avcc));
+ if (IsFormatValid()) {
+ scoped_ptr<AVCDecoderConfigurationRecord> avcConfig(
+ new AVCDecoderConfigurationRecord());
+ RCHECK(reader->ReadChild(avcConfig.get()));
+ frame_bitstream_converter = make_scoped_refptr(
+ new AVCBitstreamConverter(avcConfig.Pass()));
+ }
return true;
}
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h
index e932dc5..666ad7e 100644
--- a/media/formats/mp4/box_definitions.h
+++ b/media/formats/mp4/box_definitions.h
@@ -207,10 +207,9 @@ struct MEDIA_EXPORT VideoSampleEntry : Box {
PixelAspectRatioBox pixel_aspect;
ProtectionSchemeInfo sinf;
- // Currently expected to be present regardless of format.
- AVCDecoderConfigurationRecord avcc;
-
bool IsFormatValid() const;
+
+ scoped_refptr<BitstreamConverter> frame_bitstream_converter;
};
struct MEDIA_EXPORT ElementaryStreamDescriptor : Box {
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 00d6bce..0c64e35 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -387,29 +387,6 @@ void MP4StreamParser::OnEncryptedMediaInitData(
encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data);
}
-bool MP4StreamParser::PrepareAVCBuffer(
- const AVCDecoderConfigurationRecord& avc_config,
- std::vector<uint8>* frame_buf,
- std::vector<SubsampleEntry>* subsamples) const {
- // Convert the AVC NALU length fields to Annex B headers, as expected by
- // decoding libraries. Since this may enlarge the size of the buffer, we also
- // update the clear byte count for each subsample if encryption is used to
- // account for the difference in size between the length prefix and Annex B
- // start code.
- RCHECK(AVC::ConvertFrameToAnnexB(avc_config.length_size, frame_buf,
- subsamples));
-
- if (runs_->is_keyframe()) {
- // If this is a keyframe, we (re-)inject SPS and PPS headers at the start of
- // a frame. If subsample info is present, we also update the clear byte
- // count for that first subsample.
- RCHECK(AVC::InsertParamSetsAnnexB(avc_config, frame_buf, subsamples));
- }
-
- DCHECK(AVC::IsValidAnnexB(*frame_buf, *subsamples));
- return true;
-}
-
bool MP4StreamParser::PrepareAACBuffer(
const AAC& aac_config, std::vector<uint8>* frame_buf,
std::vector<SubsampleEntry>* subsamples) const {
@@ -500,8 +477,9 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers,
std::vector<uint8> frame_buf(buf, buf + runs_->sample_size());
if (video) {
- if (!PrepareAVCBuffer(runs_->video_description().avcc,
- &frame_buf, &subsamples)) {
+ DCHECK(runs_->video_description().frame_bitstream_converter);
+ if (!runs_->video_description().frame_bitstream_converter->ConvertFrame(
+ &frame_buf, runs_->is_keyframe(), &subsamples)) {
MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AVC sample for decode";
*err = true;
return false;
diff --git a/media/formats/mp4/mp4_stream_parser.h b/media/formats/mp4/mp4_stream_parser.h
index dad7df1..2ffe640 100644
--- a/media/formats/mp4/mp4_stream_parser.h
+++ b/media/formats/mp4/mp4_stream_parser.h
@@ -68,9 +68,6 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser {
void ChangeState(State new_state);
bool EmitConfigs();
- bool PrepareAVCBuffer(const AVCDecoderConfigurationRecord& avc_config,
- std::vector<uint8>* frame_buf,
- std::vector<SubsampleEntry>* subsamples) const;
bool PrepareAACBuffer(const AAC& aac_config,
std::vector<uint8>* frame_buf,
std::vector<SubsampleEntry>* subsamples) const;
diff --git a/media/media.gyp b/media/media.gyp
index 121cd80..79980a4 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1070,6 +1070,8 @@
'formats/mp4/aac.h',
'formats/mp4/avc.cc',
'formats/mp4/avc.h',
+ 'formats/mp4/bitstream_converter.cc',
+ 'formats/mp4/bitstream_converter.h',
'formats/mp4/box_definitions.cc',
'formats/mp4/box_definitions.h',
'formats/mp4/box_reader.cc',