diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-04 20:34:14 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-04 20:34:14 +0000 |
commit | 58023bea8fa444c4ac08c12c825dcc79b5954abe (patch) | |
tree | d4d4ce8dc812b8118aaa3e49d6465265cf19aad8 /media | |
parent | b781e774ae4f5d579c8e9122ea9baafb1f54261a (diff) | |
download | chromium_src-58023bea8fa444c4ac08c12c825dcc79b5954abe.zip chromium_src-58023bea8fa444c4ac08c12c825dcc79b5954abe.tar.gz chromium_src-58023bea8fa444c4ac08c12c825dcc79b5954abe.tar.bz2 |
Reworked player_x11:
- Turned support for EGL image ON for OpenMAX decoding.
- Added simple fix for compilation issue due to missing definition for MessageLoop.
- Added changes to GLES Video Renderer to use EGL image.
- Added H264BitstreamConverter and H264BitstreamConverterFFmpegAdaptor classes to Chromium.
- Introduced new h264 bitstream converter to FFmpegDemuxer
- Added h264 bitstream converter related classes to media targets and introduced new target for unit testing bitstream converter.
Patch by vmr@chromium.org:
http://codereview.chromium.org/6260010/
BUG=None
TEST=Test H.264 decode clip with player_x11 OpenMAX enabled.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73839 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/h264_bitstream_converter.cc | 314 | ||||
-rw-r--r-- | media/base/h264_bitstream_converter.h | 124 | ||||
-rw-r--r-- | media/base/h264_bitstream_converter_unittest.cc | 472 | ||||
-rw-r--r-- | media/filters/bitstream_converter.h | 9 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 9 | ||||
-rw-r--r-- | media/filters/ffmpeg_h264_bitstream_converter.cc | 101 | ||||
-rw-r--r-- | media/filters/ffmpeg_h264_bitstream_converter.h | 67 | ||||
-rw-r--r-- | media/filters/ffmpeg_h264_bitstream_converter_unittest.cc | 443 | ||||
-rw-r--r-- | media/media.gyp | 10 | ||||
-rw-r--r-- | media/tools/player_x11/gles_video_renderer.cc | 8 | ||||
-rw-r--r-- | media/tools/player_x11/gles_video_renderer.h | 1 |
11 files changed, 1553 insertions, 5 deletions
diff --git a/media/base/h264_bitstream_converter.cc b/media/base/h264_bitstream_converter.cc new file mode 100644 index 0000000..bdf6363 --- /dev/null +++ b/media/base/h264_bitstream_converter.cc @@ -0,0 +1,314 @@ +// Copyright (c) 2011 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/base/h264_bitstream_converter.h" + +#include "base/logging.h" + +namespace media { + +static const uint8 kStartCodePrefix[3] = {0, 0, 1}; + +// Helper function which determines whether NAL unit of given type marks +// access unit boundary. +static bool IsAccessUnitBoundaryNal(int nal_unit_type) { + // Check if this packet marks access unit boundary by checking the + // packet type. + if (nal_unit_type == 6 || // Supplemental enhancement information + nal_unit_type == 7 || // Picture parameter set + nal_unit_type == 8 || // Sequence parameter set + nal_unit_type == 9 || // Access unit delimiter + (nal_unit_type >= 14 && nal_unit_type <= 18)) { // Reserved types + return true; + } + return false; +} + +H264BitstreamConverter::H264BitstreamConverter() + : configuration_processed_(false), + first_nal_unit_in_access_unit_(true), + nal_unit_length_field_width_(0) { +} + +H264BitstreamConverter::~H264BitstreamConverter() {} + +uint32 H264BitstreamConverter::ParseConfigurationAndCalculateSize( + const uint8* configuration_record, + uint32 configuration_record_size) { + // FFmpeg's AVCodecContext's extradata field contains the Decoder Specific + // Information from MP4 headers that contain the H.264 SPS and PPS members. + // ISO 14496-15 Chapter 5.2.4 AVCDecoderConfigurationRecord. + // AVCConfigurationRecord must be at least 7 bytes long. + if (configuration_record == NULL || configuration_record_size < 7) { + return 0; // Error: invalid input + } + const uint8* decoder_configuration = configuration_record; + uint32 parameter_set_size_bytes = 0; + + // We can skip the four first bytes as they're only profile information + decoder_configuration += 4; + // Fifth byte's two LSBs contain the interleaving field's size minus one + uint8 size_of_len_field = (*decoder_configuration & 0x3) + 1; + if (size_of_len_field != 1 && size_of_len_field != 2 && + size_of_len_field != 4) { + return 0; // Error: invalid input, NAL unit field len is not correct + } + decoder_configuration++; + // Sixth byte's five LSBs contain the number of SPSs + uint8 sps_count = *decoder_configuration & 0x1F; + decoder_configuration++; + // Then we have N * SPS's with two byte length field and actual SPS + while (sps_count-- > 0) { + if ((decoder_configuration - configuration_record) + 2 > + static_cast<int32>(configuration_record_size)) { + return 0; // Error: ran out of data + } + uint16 sps_len = decoder_configuration[0] << 8 | decoder_configuration[1]; + decoder_configuration += 2; + // write the SPS to output, always with zero byte + start code prefix + parameter_set_size_bytes += 1 + sizeof(kStartCodePrefix); + decoder_configuration += sps_len; + parameter_set_size_bytes += sps_len; + } + // Then we have the numner of pps in one byte + uint8 pps_count = *decoder_configuration; + decoder_configuration++; + // And finally, we have N * PPS with two byte length field and actual PPS + while (pps_count-- > 0) { + if ((decoder_configuration - configuration_record) + 2 > + static_cast<int32>(configuration_record_size)) { + return 0; // Error: ran out of data + } + uint16 pps_len = decoder_configuration[0] << 8 | decoder_configuration[1]; + decoder_configuration += 2; + // write the SPS to output, always with zero byte + start code prefix + parameter_set_size_bytes += 1 + sizeof(kStartCodePrefix); + decoder_configuration += pps_len; + parameter_set_size_bytes += pps_len; + } + // We're done processing the AVCDecoderConfigurationRecord, + // store the needed information for parsing actual payload + nal_unit_length_field_width_ = size_of_len_field; + configuration_processed_ = true; + return parameter_set_size_bytes; +} + +uint32 H264BitstreamConverter::CalculateNeededOutputBufferSize( + const uint8* input, + uint32 input_size) const { + uint32 output_size = 0; + uint32 data_left = input_size; + bool first_nal_in_this_access_unit = first_nal_unit_in_access_unit_; + + if (input == NULL || input_size == 0) { + return 0; // Error: invalid input data + } + if (!configuration_processed_) { + return 0; // Error: configuration not handled, we don't know nal unit width + } + CHECK(nal_unit_length_field_width_ == 1 || + nal_unit_length_field_width_ == 2 || + nal_unit_length_field_width_ == 4); + + // Then add the needed size for the actual packet + while (data_left > 0) { + // Read the next NAL unit length from the input buffer + uint8 size_of_len_field; + uint32 nal_unit_length; + for (nal_unit_length = 0, size_of_len_field = nal_unit_length_field_width_; + size_of_len_field > 0; + input++, size_of_len_field--, data_left--) { + nal_unit_length <<= 8; + nal_unit_length |= *input; + } + + if (nal_unit_length == 0) { + break; // Signifies that no more data left in the buffer + } else if (nal_unit_length > data_left) { + return 0; // Error: Not enough data for correct conversion + } + data_left -= nal_unit_length; + + // five least significant bits of first NAL unit byte signify nal_unit_type + int nal_unit_type = *input & 0x1F; + if (first_nal_in_this_access_unit || + IsAccessUnitBoundaryNal(nal_unit_type)) { + output_size += 1; // Extra zero_byte for these nal units + first_nal_in_this_access_unit = false; + } + // Start code prefix + output_size += sizeof(kStartCodePrefix); + // Actual NAL unit size + output_size += nal_unit_length; + input += nal_unit_length; + first_nal_in_this_access_unit = false; + // No need for trailing zero bits + } + return output_size; +} + +bool H264BitstreamConverter::ConvertAVCDecoderConfigurationRecordToByteStream( + const uint8* input, + uint32 input_size, + uint8* output, + uint32* output_size) { + uint8* outscan = output; + // FFmpeg's AVCodecContext's extradata field contains the Decoder Specific + // Information from MP4 headers that contain the H.264 SPS and PPS members. + // ISO 14496-15 Chapter 5.2.4 AVCDecoderConfigurationRecord. + const uint8* decoder_configuration = input; + uint32 decoderconfiguration_size = input_size; + uint32 out_size = 0; + + if (decoder_configuration == NULL || decoderconfiguration_size == 0) { + return 0; // Error: input invalid + } + + // We can skip the four first bytes as they're only profile information. + decoder_configuration += 4; + // Fifth byte's two LSBs contain the interleaving field's size minus one + uint8 size_of_len_field = (*decoder_configuration & 0x3) + 1; + if (size_of_len_field != 1 && size_of_len_field != 2 && + size_of_len_field != 4) { + return 0; // Error: invalid input, NAL unit field len is not correct + } + decoder_configuration++; + // Sixth byte's five LSBs contain the number of SPSs + uint8 sps_count = *decoder_configuration & 0x1F; + decoder_configuration++; + // Then we have N * SPS's with two byte length field and actual SPS + while (sps_count-- > 0) { + uint16 sps_len = decoder_configuration[0] << 8 | + decoder_configuration[1]; + decoder_configuration += 2; + if (out_size + 1 + sizeof(kStartCodePrefix) + sps_len > + *output_size) { + *output_size = 0; + return 0; // too small output buffer; + } + // write the SPS to output, always with zero byte + start code prefix + *outscan = 0; // zero byte + outscan += 1; + memcpy(outscan, kStartCodePrefix, sizeof(kStartCodePrefix)); + outscan += sizeof(kStartCodePrefix); + memcpy(outscan, decoder_configuration, sps_len); + decoder_configuration += sps_len; + outscan += sps_len; + out_size += 1 + sizeof(kStartCodePrefix) + sps_len; + } + // Then we have the numner of pps in one byte + uint8 pps_count = *decoder_configuration; + decoder_configuration++; + // And finally, we have N * PPS with two byte length field and actual PPS + while (pps_count-- > 0) { + uint16 pps_len = decoder_configuration[0] << 8 | decoder_configuration[1]; + decoder_configuration += 2; + if (out_size + 1 + sizeof(kStartCodePrefix) + pps_len > + *output_size) { + *output_size = 0; + return 0; // too small output buffer; + } + // write the SPS to output, always with zero byte + start code prefix + *outscan = 0; // zero byte + outscan += 1; + memcpy(outscan, kStartCodePrefix, sizeof(kStartCodePrefix)); + outscan += sizeof(kStartCodePrefix); + memcpy(outscan, decoder_configuration, pps_len); + decoder_configuration += pps_len; + outscan += pps_len; + out_size += 1 + sizeof(kStartCodePrefix) + pps_len; + } + // We're done processing the AVCDecoderConfigurationRecord, store the needed + // information + nal_unit_length_field_width_ = size_of_len_field; + configuration_processed_ = true; + *output_size = out_size; + return true; +} + +bool H264BitstreamConverter::ConvertNalUnitStreamToByteStream( + const uint8* input, uint32 input_size, + uint8* output, uint32* output_size) { + const uint8* inscan = input; // We read the input from here progressively + uint8* outscan = output; // We write the output to here progressively + uint32 data_left = input_size; + + if (inscan == NULL || input_size == 0 || + outscan == NULL || *output_size == 0) { + *output_size = 0; + return false; // Error: invalid input + } + + // NAL unit width should be known at this point + CHECK(nal_unit_length_field_width_ == 1 || + nal_unit_length_field_width_ == 2 || + nal_unit_length_field_width_ == 4); + + // Do the actual conversion for the actual input packet + while (data_left > 0) { + uint8 i; + uint32 nal_unit_length; + + // Read the next NAL unit length from the input buffer by scanning + // the input stream with the specific length field width + for (nal_unit_length = 0, i = nal_unit_length_field_width_; + i > 0 && data_left > 0; + inscan++, i--, data_left--) { + nal_unit_length <<= 8; + nal_unit_length |= *inscan; + } + + if (nal_unit_length == 0) { + break; // Successful conversion, end of buffer + } else if (nal_unit_length > data_left) { + *output_size = 0; + return false; // Error: not enough data for correct conversion + } + + uint32 start_code_len; + first_nal_unit_in_access_unit_ ? + start_code_len = sizeof(kStartCodePrefix) + 1 : + start_code_len = sizeof(kStartCodePrefix); + if (static_cast<uint32>(outscan - output) + + start_code_len + nal_unit_length > *output_size) { + *output_size = 0; + return false; // Error: too small output buffer + } + + // Five least significant bits of first NAL unit byte signify + // nal_unit_type. + int nal_unit_type = *inscan & 0x1F; + + // Check if this packet marks access unit boundary by checking the + // packet type. + if (IsAccessUnitBoundaryNal(nal_unit_type)) { + first_nal_unit_in_access_unit_ = true; + } + + // Write extra zero-byte before start code prefix if this packet + // signals next access unit. + if (first_nal_unit_in_access_unit_) { + *outscan = 0; + outscan++; + first_nal_unit_in_access_unit_ = false; + } + + // No need to write leading zero bits. + // Write start-code prefix. + memcpy(outscan, kStartCodePrefix, sizeof(kStartCodePrefix)); + outscan += sizeof(kStartCodePrefix); + // Then write the actual NAL unit from the input buffer. + memcpy(outscan, inscan, nal_unit_length); + inscan += nal_unit_length; + data_left -= nal_unit_length; + outscan += nal_unit_length; + // No need for trailing zero bits. + } + // Successful conversion, output the freshly allocated bitstream buffer. + *output_size = static_cast<uint32>(outscan - output); + return true; +} + +} // namespace media + diff --git a/media/base/h264_bitstream_converter.h b/media/base/h264_bitstream_converter.h new file mode 100644 index 0000000..bce1e23b --- /dev/null +++ b/media/base/h264_bitstream_converter.h @@ -0,0 +1,124 @@ +// Copyright (c) 2011 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_BASE_H264_BITSTREAM_CONVERTER_H_ +#define MEDIA_BASE_H264_BITSTREAM_CONVERTER_H_ + +#include "base/basictypes.h" + +namespace media { + +// H264BitstreamConverter is a class to convert H.264 bitstream from +// MP4 format (as specified in ISO/IEC 14496-15) into H.264 bytestream +// (as specified in ISO/IEC 14496-10 Annex B). +class H264BitstreamConverter { + public: + H264BitstreamConverter(); + ~H264BitstreamConverter(); + + // Parses the global AVCDecoderConfigurationRecord from the file format's + // headers. Converter will remember the field length from the configuration + // headers after this. + // + // Parameters + // configuration_record + // Pointer to buffer containing AVCDecoderConfigurationRecord. + // configuration_record_size + // Size of the buffer in bytes. + // + // Returns + // Required buffer size for AVCDecoderConfigurationRecord when converted + // to bytestream format, or 0 if could not determine the configuration + // from the input buffer. + uint32 ParseConfigurationAndCalculateSize(const uint8* configuration_record, + uint32 configuration_record_size); + + // Calculates needed buffer size for the bitstream converted into bytestream. + // Lightweight implementation that does not do the actual conversion. + // + // Parameters + // configuration_record + // Pointer to buffer containing AVCDecoderConfigurationRecord. + // configuration_record_size + // Size of the buffer in bytes. + // + // Returns + // Required buffer size for the input NAL unit buffer when converted + // to bytestream format, or 0 if could not determine the configuration + // from the input buffer. + uint32 CalculateNeededOutputBufferSize(const uint8* input, + uint32 input_size) const; + + // ConvertParameterSetsToByteStream converts the + // AVCDecoderConfigurationRecord from the MP4 headers to bytestream format. + // Client is responsible for making sure the output buffer is large enough + // to hold the output data. Client can precalculate the needed output buffer + // size by using ParseConfigurationAndCalculateSize. + // + // In case of failed conversion object H264BitstreamConverter may have written + // some bytes to buffer pointed by pinput but user should ignore those bytes. + // None of the outputs should be considered valid. + // + // Parameters + // pinput + // Pointer to buffer containing AVCDecoderConfigurationRecord. + // input_size + // Size of the buffer in bytes. + // poutput + // Pointer to buffer where the output should be written to. + // poutput_size (i/o) + // Pointer to the size of the output buffer. Will contain the number of + // bytes written to output after successful call. + // + // Returns + // true if successful conversion + // false if conversion not successful (poutput_size will hold the amount + // of converted data) + bool ConvertAVCDecoderConfigurationRecordToByteStream(const uint8* input, + uint32 input_size, + uint8* output, + uint32* output_size); + + // ConvertNalUnitStreamToByteStream converts the NAL unit from MP4 format + // to bytestream format. Client is responsible for making sure the output + // buffer is large enough to hold the output data. Client can precalculate the + // needed output buffer size by using CalculateNeededOutputBufferSize. + // + // In case of failed conversion object H264BitstreamConverter may have written + // some bytes to buffer pointed by pinput but user should ignore those bytes. + // None of the outputs should be considered valid. + // + // Parameters + // pinput + // Pointer to buffer containing AVCDecoderConfigurationRecord. + // input_size + // Size of the buffer in bytes. + // poutput + // Pointer to buffer where the output should be written to. + // poutput_size (i/o) + // Pointer to the size of the output buffer. Will contain the number of + // bytes written to output after successful call. + // + // Returns + // true if successful conversion + // false if conversion not successful (poutput_size will hold the amount + // of converted data) + bool ConvertNalUnitStreamToByteStream(const uint8* input, uint32 input_size, + uint8* output, uint32* output_size); + + private: + // Flag for indicating whether global parameter sets have been processed. + bool configuration_processed_; + // Flag for indicating whether next NAL unit starts new access unit. + bool first_nal_unit_in_access_unit_; + // Variable to hold interleaving field's length in bytes. + uint8 nal_unit_length_field_width_; + + DISALLOW_COPY_AND_ASSIGN(H264BitstreamConverter); +}; + +} // namespace media + +#endif // MEDIA_BASE_H264_BITSTREAM_CONVERTER_H_ + diff --git a/media/base/h264_bitstream_converter_unittest.cc b/media/base/h264_bitstream_converter_unittest.cc new file mode 100644 index 0000000..97ccaaf --- /dev/null +++ b/media/base/h264_bitstream_converter_unittest.cc @@ -0,0 +1,472 @@ +// Copyright (c) 2011 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 "base/scoped_ptr.h" +#include "media/base/h264_bitstream_converter.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +class H264BitstreamConverterTest : public testing::Test { + protected: + H264BitstreamConverterTest() {} + + virtual ~H264BitstreamConverterTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(H264BitstreamConverterTest); +}; + +static const uint8 kHeaderDataOkWithFieldLen4[] = { + 0x01, 0x42, 0x00, 0x28, 0xFF, 0xE1, 0x00, 0x08, 0x67, 0x42, 0x00, 0x28, + 0xE9, 0x05, 0x89, 0xC8, 0x01, 0x00, 0x04, 0x68, 0xCE, 0x06, 0xF2, 0x00 +}; + +static const uint8 kPacketDataOkWithFieldLen4[] = { + 0x00, 0x00, 0x0B, 0xF7, 0x65, 0xB8, 0x40, 0x57, 0x0B, 0xF0, + 0xDF, 0xF8, 0x00, 0x1F, 0x78, 0x98, 0x54, 0xAC, 0xF2, 0x00, 0x04, 0x9D, 0x26, + 0xE0, 0x3B, 0x5C, 0x00, 0x0A, 0x00, 0x8F, 0x9E, 0x86, 0x63, 0x1B, 0x46, 0xE7, + 0xD6, 0x45, 0x88, 0x88, 0xEA, 0x10, 0x89, 0x79, 0x01, 0x34, 0x30, 0x01, 0x8E, + 0x7D, 0x1A, 0x39, 0x45, 0x4E, 0x69, 0x86, 0x12, 0xF2, 0xE7, 0xCF, 0x50, 0xF8, + 0x26, 0x54, 0x17, 0xBE, 0x3F, 0xC4, 0x80, 0x32, 0xD8, 0x02, 0x32, 0xE4, 0xAE, + 0xDD, 0x39, 0x11, 0x8E, 0x54, 0x42, 0xAE, 0xBD, 0x12, 0xA4, 0xCE, 0xE2, 0x98, + 0x91, 0x05, 0xC4, 0xA8, 0x20, 0xC7, 0xB3, 0xD9, 0x47, 0x73, 0x09, 0xD5, 0xCF, + 0x62, 0x57, 0x3F, 0xFF, 0xFD, 0xB9, 0x94, 0x2B, 0x3D, 0x12, 0x1A, 0x84, 0x0B, + 0x28, 0xAD, 0x5C, 0x9E, 0x5C, 0xC3, 0xBB, 0xBD, 0x7F, 0xFE, 0x09, 0x87, 0x74, + 0x39, 0x1C, 0xA5, 0x0E, 0x44, 0xD8, 0x5D, 0x41, 0xDB, 0xAA, 0xBC, 0x05, 0x16, + 0xA3, 0x98, 0xEE, 0xEE, 0x9C, 0xA0, 0xF1, 0x23, 0x90, 0xF0, 0x5E, 0x9F, 0xF4, + 0xFA, 0x7F, 0x4B, 0x69, 0x66, 0x49, 0x52, 0xDD, 0xD6, 0xC0, 0x0F, 0x8C, 0x6E, + 0x80, 0xDD, 0x7A, 0xDF, 0x10, 0xCD, 0x4B, 0x54, 0x6F, 0xFC, 0x7D, 0x34, 0xBA, + 0x8B, 0xD4, 0xD9, 0x30, 0x18, 0x9F, 0x39, 0x04, 0x9F, 0xCB, 0xDB, 0x1B, 0xA7, + 0x70, 0x96, 0xAF, 0xFF, 0x6F, 0xB5, 0xBF, 0x58, 0x01, 0x98, 0xCD, 0xF2, 0x66, + 0x28, 0x1A, 0xC4, 0x9E, 0x58, 0x40, 0x39, 0xAE, 0x07, 0x11, 0x3F, 0xF2, 0x9B, + 0x06, 0x9C, 0xB8, 0xC9, 0x16, 0x12, 0x09, 0x8E, 0xD2, 0xD4, 0xF5, 0xC6, 0x77, + 0x40, 0x0F, 0xFD, 0x12, 0x19, 0x55, 0x1A, 0x8E, 0x9C, 0x18, 0x8B, 0x0D, 0x18, + 0xFA, 0xBA, 0x7F, 0xBB, 0x83, 0xBB, 0x85, 0xA0, 0xCC, 0xAF, 0xF6, 0xEA, 0x81, + 0x10, 0x18, 0x8E, 0x10, 0x00, 0xCB, 0x7F, 0x27, 0x08, 0x06, 0xDE, 0x3C, 0x20, + 0xE5, 0xFE, 0xCC, 0x4F, 0xB3, 0x41, 0xE0, 0xCC, 0x4C, 0x26, 0xC1, 0xC0, 0x2C, + 0x16, 0x12, 0xAA, 0x04, 0x83, 0x51, 0x4E, 0xCA, 0x00, 0xCF, 0x42, 0x9C, 0x06, + 0x2D, 0x06, 0xDD, 0x1D, 0x08, 0x75, 0xE0, 0x89, 0xC7, 0x62, 0x68, 0x2E, 0xBF, + 0x4D, 0x2D, 0x0A, 0xC4, 0x86, 0xF6, 0x2F, 0xA1, 0x49, 0xA7, 0x0F, 0xDB, 0x1F, + 0x82, 0xEC, 0xC1, 0x62, 0xFB, 0x7F, 0xF1, 0xAE, 0xA6, 0x1A, 0xD5, 0x6B, 0x06, + 0x5E, 0xB6, 0x02, 0x50, 0xAE, 0x2D, 0xF9, 0xD9, 0x95, 0xAD, 0x01, 0x8C, 0x53, + 0x01, 0xAF, 0xCE, 0xE5, 0xA5, 0xBB, 0x95, 0x8A, 0x85, 0x70, 0x77, 0xE3, 0x9A, + 0x68, 0x1B, 0xDF, 0x47, 0xF9, 0xF4, 0xBD, 0x80, 0x7D, 0x76, 0x9A, 0x69, 0xFC, + 0xBE, 0x14, 0x0D, 0x87, 0x09, 0x12, 0x98, 0x20, 0x05, 0x46, 0xB7, 0xAE, 0x10, + 0xB7, 0x01, 0xB7, 0xDE, 0x3B, 0xDD, 0x7A, 0x8A, 0x55, 0x73, 0xAD, 0xDF, 0x69, + 0xDE, 0xD0, 0x51, 0x97, 0xA0, 0xE6, 0x5E, 0xBA, 0xBA, 0x80, 0x0F, 0x4E, 0x9A, + 0x68, 0x36, 0xE6, 0x9F, 0x5B, 0x39, 0xC0, 0x90, 0xA1, 0xC0, 0xC3, 0x82, 0xE4, + 0x50, 0xEA, 0x60, 0x7A, 0xDD, 0x5F, 0x8B, 0x5F, 0xAF, 0xFC, 0x74, 0xAF, 0xDC, + 0x56, 0xF7, 0x2E, 0x3E, 0x97, 0x6E, 0x2B, 0xF3, 0xAF, 0xFE, 0x7D, 0x32, 0xDC, + 0x56, 0xF8, 0xAF, 0xB5, 0xA3, 0xBB, 0x00, 0x5B, 0x84, 0x3D, 0x9F, 0x0B, 0x40, + 0x88, 0x61, 0x5F, 0x4F, 0x4F, 0xB0, 0xB3, 0x07, 0x81, 0x3E, 0xF2, 0xFB, 0x50, + 0xCA, 0x77, 0x40, 0x12, 0xA8, 0xE6, 0x11, 0x8E, 0xD6, 0x8A, 0xC6, 0xD6, 0x8C, + 0x1D, 0x63, 0x55, 0x3D, 0x34, 0xEA, 0xC3, 0xC6, 0x6A, 0xD2, 0x8C, 0xB0, 0x1D, + 0x5E, 0x4A, 0x7A, 0x8B, 0xD5, 0x99, 0x80, 0x84, 0x32, 0xFB, 0xB7, 0x02, 0x6E, + 0x61, 0xFE, 0xAC, 0x1B, 0x5D, 0x10, 0x23, 0x24, 0xC3, 0x8C, 0x7B, 0x58, 0x2C, + 0x4D, 0x04, 0x74, 0x84, 0x25, 0x10, 0x4E, 0x94, 0x29, 0x4D, 0x88, 0xAE, 0x65, + 0x53, 0xB9, 0x95, 0x4E, 0xE7, 0xDD, 0xEE, 0xF2, 0x70, 0x1F, 0x26, 0x4F, 0xA8, + 0xBC, 0x3D, 0x35, 0x02, 0x3B, 0xC0, 0x98, 0x70, 0x38, 0x18, 0xE5, 0x1E, 0x05, + 0xAC, 0x28, 0xAA, 0x46, 0x1A, 0xB0, 0x19, 0x99, 0x18, 0x35, 0x78, 0x1E, 0x41, + 0x60, 0x0D, 0x4F, 0x7E, 0xEC, 0x37, 0xC3, 0x30, 0x73, 0x2A, 0x69, 0xFE, 0xEF, + 0x27, 0xEE, 0x13, 0xCC, 0xD0, 0xDB, 0xE6, 0x45, 0xEC, 0x5C, 0xB5, 0x71, 0x54, + 0x2E, 0xB1, 0xE9, 0x88, 0xB4, 0x3F, 0x6F, 0xFD, 0xF7, 0xFF, 0x9D, 0x2D, 0x52, + 0x2E, 0xAE, 0xC9, 0x95, 0xDE, 0xBF, 0xDF, 0xFF, 0xBF, 0x21, 0xB3, 0x2B, 0xF5, + 0xF7, 0xF7, 0xD1, 0xA0, 0xF0, 0x76, 0x68, 0x37, 0xDB, 0x8F, 0x85, 0x4D, 0xA8, + 0x1A, 0xF9, 0x7F, 0x75, 0xA7, 0x93, 0xF5, 0x03, 0xC1, 0xF2, 0x60, 0x8A, 0x92, + 0x53, 0xF5, 0xD1, 0xC1, 0x56, 0x4B, 0x68, 0x05, 0x16, 0x88, 0x61, 0xE7, 0x14, + 0xC8, 0x0D, 0xF0, 0xDF, 0xEF, 0x46, 0x4A, 0xED, 0x0B, 0xD1, 0xD1, 0xD1, 0xA4, + 0x85, 0xA3, 0x2C, 0x1D, 0xDE, 0x45, 0x14, 0xA1, 0x8E, 0xA8, 0xD9, 0x8C, 0xAB, + 0x47, 0x31, 0xF1, 0x00, 0x15, 0xAD, 0x80, 0x20, 0xAA, 0xE4, 0x57, 0xF8, 0x05, + 0x14, 0x58, 0x0B, 0xD3, 0x63, 0x00, 0x8F, 0x44, 0x15, 0x7F, 0x19, 0xC7, 0x0A, + 0xE0, 0x49, 0x32, 0xFE, 0x36, 0x0E, 0xF3, 0x66, 0x10, 0x2B, 0x11, 0x73, 0x3D, + 0x19, 0x92, 0x22, 0x20, 0x75, 0x1F, 0xF1, 0xDB, 0x96, 0x73, 0xCF, 0x1B, 0x53, + 0xFF, 0xD2, 0x23, 0xF2, 0xB6, 0xAA, 0xB6, 0x44, 0xA3, 0x73, 0x7E, 0x00, 0x2D, + 0x4D, 0x4D, 0x87, 0xE0, 0x84, 0x55, 0xD6, 0x03, 0xB8, 0xD8, 0x90, 0xEF, 0xC0, + 0x76, 0x5D, 0x69, 0x02, 0x00, 0x0E, 0x17, 0xD0, 0x02, 0x96, 0x50, 0xEA, 0xAB, + 0xBF, 0x0D, 0xAF, 0xCB, 0xD3, 0xFF, 0xAA, 0x9D, 0x7F, 0xD6, 0xBD, 0x2C, 0x14, + 0xB4, 0xCD, 0x20, 0x73, 0xB4, 0xF4, 0x38, 0x96, 0xDE, 0xB0, 0x6B, 0xE5, 0x1B, + 0xFD, 0x0E, 0x0B, 0xA4, 0x81, 0xBF, 0xC8, 0xA0, 0x21, 0x76, 0x7B, 0x25, 0x3F, + 0xE6, 0x84, 0x40, 0x1A, 0xDA, 0x25, 0x5A, 0xFF, 0x73, 0x6B, 0x14, 0x1B, 0xF7, + 0x08, 0xFA, 0x26, 0x73, 0x7A, 0x58, 0x02, 0x1A, 0xE6, 0x63, 0xB6, 0x45, 0x7B, + 0xE3, 0xE0, 0x80, 0x14, 0x42, 0xA8, 0x7D, 0xF3, 0x80, 0x9B, 0x01, 0x43, 0x82, + 0x82, 0x8C, 0xBE, 0x0D, 0xFD, 0xAE, 0x88, 0xA8, 0xB9, 0xC3, 0xEE, 0xFF, 0x46, + 0x00, 0x84, 0xE6, 0xB4, 0x0C, 0xA9, 0x66, 0xC6, 0x74, 0x72, 0xAA, 0xA4, 0x3A, + 0xB0, 0x1B, 0x06, 0xB4, 0xDB, 0xE8, 0xC2, 0x17, 0xA2, 0xBC, 0xBE, 0x5C, 0x0F, + 0x2A, 0x76, 0xD5, 0xEE, 0x39, 0x36, 0x7C, 0x25, 0x94, 0x15, 0x3C, 0xC9, 0xB9, + 0x93, 0x07, 0x19, 0xAF, 0xE6, 0x70, 0xC3, 0xF5, 0xD4, 0x17, 0x87, 0x57, 0x77, + 0x7D, 0xCF, 0x0D, 0xDD, 0xDE, 0xB7, 0xFF, 0xB4, 0xDA, 0x20, 0x45, 0x1A, 0x45, + 0xF4, 0x58, 0x01, 0xBC, 0xEB, 0x3F, 0x16, 0x7F, 0x4C, 0x15, 0x84, 0x8C, 0xE5, + 0xF6, 0x96, 0xA6, 0xA1, 0xB9, 0xB2, 0x7F, 0x6B, 0xFF, 0x31, 0xF2, 0xF5, 0xC9, + 0xFF, 0x61, 0xEE, 0xB5, 0x84, 0xAE, 0x68, 0x41, 0xEA, 0xD0, 0xF0, 0xA5, 0xCE, + 0x0C, 0xE6, 0x4C, 0x6D, 0x6D, 0x94, 0x08, 0xC9, 0xA9, 0x4A, 0x60, 0x6D, 0x01, + 0x3B, 0xEF, 0x4D, 0x99, 0x8D, 0x42, 0x2A, 0x6B, 0x8A, 0xC7, 0xFA, 0xA9, 0x90, + 0x40, 0x00, 0x90, 0xF3, 0xA0, 0x75, 0x8E, 0xD5, 0xFE, 0xE7, 0xBD, 0x02, 0x87, + 0x0C, 0x7D, 0xF0, 0xAF, 0x1E, 0x5F, 0x8D, 0xC8, 0xE1, 0xD4, 0x56, 0x08, 0xBF, + 0x76, 0x80, 0xD4, 0x18, 0x89, 0x2D, 0x57, 0xDF, 0x66, 0xD0, 0x46, 0x68, 0x77, + 0x55, 0x47, 0xF5, 0x7C, 0xF7, 0xA6, 0x66, 0xD6, 0x5A, 0x64, 0x55, 0xD4, 0x80, + 0xC4, 0x55, 0xE9, 0x36, 0x3F, 0x5E, 0xE2, 0x5C, 0x7F, 0x5F, 0xCE, 0x7F, 0xE1, + 0x0C, 0x82, 0x3D, 0x6B, 0x6E, 0xA2, 0xEA, 0x3B, 0x1F, 0xE8, 0x9E, 0xC7, 0x4E, + 0x24, 0x3D, 0xDD, 0xFA, 0xEB, 0x71, 0xDF, 0xFE, 0x15, 0xFE, 0x41, 0x9B, 0xB4, + 0x4E, 0xAB, 0x51, 0xE5, 0x1F, 0x7D, 0x2D, 0xAC, 0xD0, 0x66, 0xD9, 0xA1, 0x59, + 0x78, 0xC6, 0xEF, 0xC4, 0x43, 0x08, 0x65, 0x18, 0x73, 0xDE, 0x2A, 0xAD, 0x72, + 0xE7, 0x5A, 0x7E, 0x33, 0x04, 0x72, 0x38, 0x57, 0x47, 0x73, 0x10, 0x1D, 0x88, + 0x57, 0x4C, 0xDF, 0xA7, 0x78, 0x16, 0xFB, 0x01, 0x21, 0x28, 0x2D, 0xB6, 0x7E, + 0x05, 0x18, 0x32, 0x52, 0xC3, 0x49, 0x0B, 0x32, 0x18, 0x12, 0x93, 0x54, 0x15, + 0x3B, 0xC8, 0x6D, 0x4A, 0x77, 0xEF, 0x0A, 0x46, 0x83, 0x89, 0x5C, 0x8B, 0xCB, + 0x18, 0xA6, 0xDC, 0x97, 0x6F, 0xEE, 0xEE, 0x00, 0x6A, 0xF1, 0x10, 0xFE, 0x07, + 0x0C, 0xE0, 0x53, 0xD2, 0xB8, 0x45, 0xF4, 0x6E, 0x16, 0x4B, 0xC9, 0x9C, 0xC7, + 0x93, 0x83, 0x23, 0x1D, 0x4D, 0x00, 0xB9, 0x4F, 0x86, 0x51, 0xF0, 0x29, 0x69, + 0x41, 0x21, 0xC5, 0x4A, 0xC6, 0x6D, 0xD1, 0x81, 0x38, 0xDB, 0x7C, 0x06, 0xA8, + 0x26, 0x8E, 0x71, 0x00, 0x4C, 0x44, 0x14, 0x05, 0xF2, 0x1C, 0x00, 0x49, 0xFC, + 0x29, 0x6A, 0xF9, 0x9E, 0xD1, 0x35, 0x4B, 0xB7, 0xE5, 0xDB, 0xFC, 0x01, 0x04, + 0x3F, 0x70, 0x33, 0x56, 0x87, 0x69, 0x01, 0xB4, 0xCE, 0x1C, 0x4D, 0x2E, 0x83, + 0x51, 0x51, 0xD0, 0x37, 0x3B, 0xB4, 0xBA, 0x47, 0xF5, 0xFF, 0xBF, 0xFA, 0xD5, + 0x03, 0x65, 0xD3, 0x28, 0x9F, 0x38, 0x57, 0xFE, 0x71, 0xD8, 0x9C, 0x16, 0xEE, + 0x72, 0x19, 0x03, 0x17, 0x6E, 0xC0, 0xEC, 0x49, 0x3D, 0x96, 0xE2, 0x30, 0x97, + 0x97, 0x84, 0x38, 0x6B, 0xE8, 0x2E, 0xAB, 0x0E, 0x2E, 0x03, 0x52, 0xBA, 0x68, + 0x55, 0xBA, 0x1D, 0x2C, 0x47, 0xAA, 0x72, 0xAE, 0x02, 0x31, 0x6E, 0xA1, 0xDC, + 0xAD, 0x0F, 0x4A, 0x46, 0xC9, 0xF2, 0xA9, 0xAB, 0xFD, 0x87, 0x89, 0x5C, 0xB3, + 0x75, 0x7E, 0xE3, 0xDE, 0x9F, 0xC4, 0x02, 0x1E, 0xA2, 0xF8, 0x8B, 0xD3, 0x00, + 0x83, 0x96, 0xC4, 0xD0, 0xB9, 0x62, 0xB9, 0x69, 0xEC, 0x56, 0xDF, 0x7D, 0x91, + 0x4B, 0x68, 0x27, 0xA8, 0x61, 0x78, 0xA7, 0x95, 0x66, 0x51, 0x41, 0xF6, 0xCE, + 0x78, 0xD3, 0x9A, 0x91, 0xA0, 0x31, 0x09, 0x47, 0xB8, 0x47, 0xB8, 0x44, 0xE1, + 0x13, 0x86, 0x7E, 0x92, 0x80, 0xC6, 0x1A, 0xF7, 0x79, 0x7E, 0xF1, 0x5D, 0x9F, + 0x17, 0x2D, 0x80, 0x00, 0x79, 0x34, 0x7D, 0xE3, 0xAD, 0x60, 0x00, 0x20, 0x07, + 0x80, 0x00, 0x40, 0x01, 0xF8, 0xA1, 0x86, 0xB1, 0xEE, 0x21, 0x63, 0x85, 0x60, + 0x51, 0x84, 0x90, 0x7E, 0x92, 0x09, 0x39, 0x1C, 0x16, 0x87, 0x5C, 0xA6, 0x09, + 0x90, 0x06, 0x34, 0x6E, 0xB8, 0x8D, 0x5D, 0xAC, 0x77, 0x97, 0xB5, 0x4D, 0x30, + 0xFD, 0x39, 0xD0, 0x50, 0x00, 0xC9, 0x98, 0x04, 0x86, 0x00, 0x0D, 0xD8, 0x3E, + 0x34, 0xC2, 0xA6, 0x25, 0xF8, 0x20, 0xCC, 0x6D, 0x9E, 0x63, 0x05, 0x30, 0xC4, + 0xC6, 0xCC, 0x54, 0x31, 0x9F, 0x3C, 0xF5, 0x86, 0xB9, 0x08, 0x18, 0xC3, 0x1E, + 0xB9, 0xA0, 0x0C, 0x45, 0x2C, 0x54, 0x32, 0x8B, 0x85, 0x86, 0x59, 0xC3, 0xB3, + 0x50, 0x5A, 0xFE, 0xBA, 0xF7, 0x4D, 0xC9, 0x9C, 0x9E, 0x01, 0xDF, 0xD7, 0x6E, + 0xB5, 0x15, 0x53, 0x08, 0x57, 0xA4, 0x71, 0x36, 0x80, 0x46, 0x05, 0x21, 0x48, + 0x7B, 0x91, 0xC8, 0xAA, 0xFF, 0x07, 0x9F, 0x78, 0x68, 0xCF, 0x3C, 0xEF, 0xFF, + 0xBC, 0xB6, 0xA2, 0x36, 0xB7, 0x9F, 0x54, 0xF6, 0x6F, 0x5D, 0xDD, 0x75, 0xD4, + 0x3C, 0x75, 0xE8, 0xCF, 0x15, 0x02, 0x5B, 0x94, 0xC3, 0xA2, 0x41, 0x63, 0xA1, + 0x14, 0xF6, 0xC0, 0x57, 0x15, 0x9F, 0x0C, 0x3F, 0x80, 0xF2, 0x98, 0xEE, 0x41, + 0x85, 0xEE, 0xBC, 0xAA, 0xE9, 0x59, 0xAA, 0xA0, 0x92, 0xCA, 0x00, 0xF3, 0x50, + 0xCC, 0xFF, 0xAD, 0x97, 0x69, 0xA7, 0xF2, 0x0B, 0x8F, 0xD7, 0xD7, 0x82, 0x3A, + 0xBB, 0x98, 0x1D, 0xCB, 0x89, 0x0B, 0x9B, 0x05, 0xF7, 0xD0, 0x1A, 0x60, 0xF3, + 0x29, 0x16, 0x12, 0xF8, 0xF4, 0xF1, 0x4A, 0x05, 0x9B, 0x57, 0x12, 0x7E, 0x3A, + 0x4A, 0x8D, 0xA6, 0xDF, 0xB6, 0xDD, 0xDF, 0xC3, 0xF0, 0xD2, 0xD4, 0xD7, 0x41, + 0xA6, 0x00, 0x76, 0x8C, 0x75, 0x08, 0xF0, 0x19, 0xD8, 0x14, 0x63, 0x55, 0x52, + 0x18, 0x30, 0x98, 0xD0, 0x3F, 0x65, 0x52, 0xB3, 0x88, 0x6D, 0x17, 0x39, 0x93, + 0xCA, 0x3B, 0xB4, 0x1D, 0x8D, 0xDF, 0xDF, 0xAD, 0x72, 0xDA, 0x74, 0xAF, 0xBD, + 0x31, 0xF9, 0x12, 0x61, 0x45, 0x29, 0x4C, 0x2B, 0x61, 0xA1, 0x12, 0x90, 0x53, + 0xE7, 0x5A, 0x9D, 0x44, 0xC8, 0x3A, 0x83, 0xDC, 0x34, 0x4C, 0x07, 0xAF, 0xDB, + 0x90, 0xCD, 0x03, 0xA4, 0x64, 0x78, 0xBD, 0x55, 0xB2, 0x56, 0x59, 0x32, 0xAB, + 0x13, 0x2C, 0xC9, 0x77, 0xF8, 0x3B, 0xDF, 0xFF, 0xAC, 0x07, 0xB9, 0x08, 0x7B, + 0xE9, 0x82, 0xB9, 0x59, 0xC7, 0xFF, 0x86, 0x2C, 0x12, 0x7C, 0xC6, 0x65, 0x3C, + 0x71, 0xB8, 0x98, 0x9F, 0xA2, 0x45, 0x03, 0xA5, 0xD9, 0xC3, 0xCF, 0xFA, 0xEB, + 0x89, 0xAD, 0x03, 0xEE, 0xDD, 0x76, 0xD3, 0x4F, 0x10, 0x6F, 0xF0, 0xC1, 0x60, + 0x0C, 0x00, 0xD4, 0x76, 0x12, 0x0A, 0x8D, 0xDC, 0xFD, 0x5E, 0x0B, 0x26, 0x2F, + 0x01, 0x1D, 0xB9, 0xE7, 0x73, 0xD4, 0xF2, 0xCB, 0xD8, 0x78, 0x21, 0x52, 0x4B, + 0x83, 0x3C, 0x44, 0x72, 0x0E, 0xB1, 0x4E, 0x37, 0xBC, 0xC7, 0x50, 0xFA, 0x07, + 0x80, 0x71, 0x10, 0x0B, 0x24, 0xD1, 0x7E, 0xDA, 0x7F, 0xA7, 0x2F, 0x40, 0xAA, + 0xD3, 0xF5, 0x44, 0x10, 0x56, 0x4E, 0x3B, 0xF1, 0x6E, 0x9A, 0xA0, 0xEA, 0x85, + 0x66, 0x16, 0xFB, 0x5C, 0x0B, 0x2B, 0x74, 0x18, 0xAF, 0x3D, 0x04, 0x3E, 0xCE, + 0x88, 0x9B, 0x3E, 0xF4, 0xB9, 0x00, 0x60, 0x0E, 0xE1, 0xE2, 0xCB, 0x12, 0xB9, + 0x6D, 0x5A, 0xC7, 0x55, 0x1D, 0xB9, 0x79, 0xAC, 0x43, 0x43, 0xE6, 0x3B, 0xDD, + 0x7E, 0x9F, 0x78, 0xD3, 0xEA, 0xA3, 0x11, 0xFF, 0xDB, 0xBB, 0xB8, 0x97, 0x37, + 0x15, 0xDB, 0xF1, 0x97, 0x96, 0xC7, 0xFC, 0xE5, 0xBF, 0xF2, 0x86, 0xC0, 0xFA, + 0x9B, 0x4C, 0x00, 0x04, 0x03, 0xA5, 0xB6, 0xB7, 0x9C, 0xD9, 0xAB, 0x09, 0x77, + 0x51, 0x18, 0x3B, 0xAD, 0x61, 0x6C, 0xFC, 0x51, 0x96, 0xFB, 0x19, 0xC8, 0x52, + 0x35, 0x07, 0x00, 0x63, 0x87, 0x14, 0x04, 0xFA, 0x7A, 0x48, 0x3E, 0x00, 0x47, + 0x29, 0x07, 0x74, 0x97, 0x74, 0x84, 0xEB, 0xB2, 0x16, 0xB2, 0x31, 0x81, 0xCE, + 0x2A, 0x31, 0xA7, 0xB1, 0xEB, 0x83, 0x34, 0x7A, 0x73, 0xD7, 0x2F, 0xFF, 0xBC, + 0xFF, 0xE5, 0xAA, 0xF2, 0xB5, 0x6E, 0x9E, 0xA5, 0x70, 0x8A, 0x8C, 0xDF, 0x6A, + 0x06, 0x16, 0xC1, 0xAB, 0x59, 0x70, 0xD9, 0x3D, 0x47, 0x7C, 0xDD, 0xEF, 0xDF, + 0x2F, 0xFF, 0x42, 0x6B, 0xBA, 0x4B, 0xBF, 0xF8, 0x7F, 0xF2, 0x03, 0x0D, 0x79, + 0xBC, 0x03, 0x76, 0x64, 0x1C, 0x0D, 0x7B, 0xD7, 0xBD, 0xB0, 0x6C, 0xD8, 0x61, + 0x17, 0x17, 0x8C, 0xED, 0x4E, 0x20, 0xEB, 0x55, 0x33, 0x39, 0xE9, 0x7E, 0xBE, + 0x8E, 0x05, 0x4B, 0x78, 0x96, 0x85, 0xCC, 0x68, 0xC9, 0x78, 0xAF, 0xAE, 0x44, + 0x36, 0x61, 0xD3, 0x53, 0xEB, 0xB3, 0x3E, 0x4F, 0x97, 0xE2, 0x8D, 0xAE, 0x90, + 0xED, 0xB5, 0x4F, 0x8E, 0xE4, 0x7A, 0x44, 0xCF, 0x9D, 0xC5, 0x77, 0x4D, 0xAB, + 0x4F, 0xE5, 0xC5, 0x73, 0xA0, 0xC8, 0xA5, 0xBB, 0x4B, 0x7D, 0xD5, 0xFB, 0xFB, + 0xFF, 0x61, 0xFD, 0xAA, 0x1A, 0x62, 0x7E, 0x3C, 0x66, 0x34, 0x15, 0x64, 0x25, + 0xEC, 0x7C, 0x9D, 0x6A, 0x64, 0x4D, 0x80, 0xD5, 0x4F, 0xFE, 0x8E, 0xEE, 0x18, + 0x53, 0xC1, 0x09, 0x51, 0xF7, 0xC0, 0xA6, 0xB2, 0x9B, 0x19, 0x2B, 0x14, 0x66, + 0x66, 0x4B, 0x39, 0x62, 0x1D, 0x84, 0xB9, 0x02, 0x84, 0xAC, 0xC1, 0xDA, 0x6C, + 0x80, 0xCD, 0x40, 0x20, 0x20, 0x19, 0x51, 0xDC, 0x2B, 0x7D, 0x5D, 0x7F, 0xE3, + 0x86, 0x8E, 0xC3, 0x35, 0xFE, 0x5C, 0xF6, 0x1C, 0xFF, 0x05, 0x9E, 0xB5, 0xB6, + 0xBB, 0xBE, 0xF7, 0x2F, 0xB7, 0xE1, 0xF5, 0x33, 0x86, 0xA0, 0x47, 0xDE, 0xF7, + 0xE9, 0x3B, 0xBE, 0x7E, 0x9B, 0x17, 0xFC, 0xFD, 0x2E, 0x40, 0x86, 0x41, 0x75, + 0xF1, 0xB2, 0x18, 0xA9, 0xDE, 0x2D, 0xD6, 0x04, 0x20, 0xA4, 0xBA, 0x81, 0xBC, + 0x1D, 0x5A, 0xD6, 0xF7, 0xF6, 0xB8, 0x42, 0xF7, 0xF5, 0x3D, 0x97, 0xAC, 0xCD, + 0x6F, 0xAD, 0xDB, 0x4F, 0x5A, 0x2E, 0x64, 0xB9, 0x5D, 0xDD, 0x8B, 0x4A, 0x35, + 0x44, 0xFE, 0x3D, 0xC6, 0x77, 0x7A, 0xBF, 0xDA, 0xAC, 0x9E, 0xB0, 0xA2, 0xB9, + 0x6C, 0xAF, 0x02, 0xDD, 0xF2, 0x71, 0x2B, 0xEF, 0xD3, 0x51, 0x0E, 0x07, 0x11, + 0xBD, 0xED, 0x39, 0x7F, 0xD9, 0xB8, 0xBD, 0xEE, 0x35, 0xE9, 0x5C, 0x67, 0x42, + 0xDA, 0x05, 0x6E, 0x39, 0xCE, 0x55, 0xFB, 0x26, 0xB7, 0x90, 0x4B, 0xDA, 0x91, + 0x48, 0xFD, 0xDE, 0xB2, 0xEC, 0x88, 0x9A, 0x46, 0x1A, 0x4C, 0xD4, 0x05, 0x12, + 0x85, 0x57, 0x37, 0x22, 0xD3, 0x0E, 0x4F, 0x79, 0xE3, 0x81, 0xA9, 0x2B, 0x5F, + 0xD7, 0x6D, 0xBD, 0x21, 0x98, 0x6F, 0x7D, 0xF5, 0x32, 0x7A, 0x6E, 0xF8, 0x20, + 0x01, 0x50, 0x90, 0x7A, 0x88, 0x3E, 0x0D, 0x57, 0xB1, 0x58, 0x65, 0xE6, 0x82, + 0xCE, 0x08, 0x69, 0x8B, 0x87, 0x62, 0x36, 0xB1, 0x7B, 0xDE, 0x74, 0xBD, 0xFE, + 0x10, 0xBE, 0x26, 0xAB, 0x7E, 0xB7, 0x8D, 0xF7, 0x83, 0x2E, 0x0F, 0xAF, 0x7E, + 0xBC, 0x17, 0x31, 0xFF, 0xB0, 0x4F, 0x7F, 0x4B, 0x13, 0x83, 0xDF, 0xEE, 0x23, + 0xD3, 0xE7, 0xC8, 0xAF, 0x75, 0xAB, 0xEA, 0xBD, 0x7D, 0xD2, 0x9D, 0xE9, 0xC1, + 0x18, 0x8B, 0x7C, 0x9F, 0x51, 0xDC, 0x37, 0xA3, 0xDB, 0xFC, 0xD4, 0x6A, 0x91, + 0x44, 0x7F, 0x72, 0xC5, 0xD9, 0xC8, 0x37, 0x38, 0x63, 0x0D, 0x59, 0x8B, 0x7F, + 0x7D, 0x96, 0xC1, 0x5F, 0x4C, 0x7C, 0x88, 0xCB, 0x65, 0x07, 0x2B, 0x0E, 0x1D, + 0x24, 0xAA, 0x20, 0x2E, 0x6C, 0x33, 0xAB, 0xEF, 0x23, 0xE5, 0xE3, 0x6C, 0xA3, + 0xA5, 0x2D, 0x01, 0xDF, 0x26, 0x92, 0x52, 0xF5, 0xE6, 0x3E, 0xE3, 0xDD, 0xC6, + 0xED, 0x42, 0x0F, 0x71, 0x7B, 0xD1, 0xF4, 0x06, 0xF6, 0x82, 0xD5, 0x13, 0xB3, + 0x60, 0x31, 0x09, 0x89, 0x63, 0x15, 0xD2, 0xCB, 0xAA, 0x77, 0xFD, 0xF4, 0xEB, + 0xF4, 0xED, 0x2E, 0xE2, 0xBA, 0x27, 0x2E, 0x74, 0xD2, 0x91, 0x7F, 0x0F, 0xDE, + 0x25, 0xFE, 0x78, 0x20, 0x05, 0x0A, 0x6A, 0xFE, 0x89, 0x14, 0x23, 0xF3, 0xF5, + 0x3A, 0x1E, 0xF3, 0x22, 0xCE, 0x12, 0x82, 0x24, 0x11, 0x05, 0x04, 0x71, 0x99, + 0xE5, 0xF0, 0xA6, 0xDB, 0x7B, 0xF5, 0x8F, 0xF9, 0x3C, 0x02, 0x0C, 0x46, 0xFD, + 0xB6, 0xEA, 0x06, 0x11, 0xF4, 0x1E, 0x7A, 0x20, 0x6A, 0x54, 0xBB, 0x4A, 0x60, + 0xB0, 0x30, 0x28, 0x9A, 0xF3, 0x3B, 0xE9, 0xBD, 0xD6, 0x04, 0xCA, 0x3A, 0x33, + 0x37, 0x5F, 0xB7, 0xAD, 0xE7, 0x9C, 0xE2, 0x95, 0x21, 0xF7, 0xB5, 0xC4, 0xF0, + 0xD1, 0x51, 0x09, 0x44, 0x3F, 0x07, 0xFC, 0x5F, 0x37, 0xFD, 0x7D, 0x7E, 0xD5, + 0xF7, 0xEB, 0x69, 0xB9, 0x54, 0x98, 0x5A, 0x2A, 0x56, 0xE3, 0xC0, 0x21, 0x57, + 0xD1, 0xEB, 0x75, 0x15, 0xED, 0xAC, 0xAF, 0x5D, 0xFF, 0xC2, 0xFE, 0x4E, 0xFB, + 0xBA, 0x13, 0xB8, 0x87, 0xFA, 0x4E, 0x5E, 0x5C, 0x24, 0x15, 0x5B, 0x2B, 0x2C, + 0x32, 0x68, 0x1F, 0x30, 0x5F, 0xC1, 0xF7, 0xE7, 0xE1, 0x9C, 0x00, 0xC1, 0x9C, + 0xB1, 0xAB, 0xFA, 0xFF, 0xC1, 0x1E, 0x72, 0xA1, 0x46, 0x9E, 0x2E, 0xCD, 0x76, + 0x96, 0x4F, 0x14, 0xDC, 0x68, 0xC1, 0x10, 0x9F, 0xDF, 0xEB, 0x5A, 0xBA, 0x8D, + 0x91, 0x4E, 0x76, 0xE9, 0x3A, 0x43, 0x2D, 0x88, 0xD2, 0x81, 0x0C, 0xEC, 0x6F, + 0xB7, 0xA4, 0x8B, 0x97, 0x4F, 0xC4, 0x1E, 0xF3, 0x0F, 0xF5, 0x66, 0x66, 0xBF, + 0x6C, 0x3F, 0xFB, 0x6E, 0x2B, 0x48, 0x6C, 0x7B, 0xD1, 0x2E, 0x64, 0xD1, 0x0B, + 0x6E, 0x5B, 0x05, 0x16, 0xDD, 0xCB, 0x1B, 0xDE, 0xA2, 0xB9, 0xA8, 0x94, 0xD6, + 0x5A, 0x5B, 0xE2, 0xC9, 0xBC, 0xD5, 0xAB, 0x64, 0x5B, 0x0F, 0x9A, 0xFD, 0xC7, + 0x2E, 0xB7, 0xEF, 0xAE, 0xE9, 0x1F, 0x32, 0xD2, 0xCA, 0xA0, 0x37, 0x63, 0x86, + 0x72, 0x41, 0x07, 0xBC, 0xAB, 0x6F, 0xFF, 0xB7, 0x16, 0xAA, 0xA9, 0x58, 0x9E, + 0x43, 0x9C, 0x22, 0x8D, 0x48, 0xCE, 0xE5, 0xEF, 0xE0, 0x7D, 0x47, 0x87, 0x5A, + 0xA8, 0x5B, 0x06, 0xA9, 0x47, 0xF0, 0x26, 0xB4, 0x99, 0xD8, 0xA3, 0x64, 0xED, + 0x73, 0xB3, 0x96, 0xB4, 0x21, 0x19, 0xA5, 0xC1, 0xDC, 0x88, 0x2E, 0xEE, 0xF2, + 0x77, 0x91, 0xEC, 0xFB, 0xD5, 0xF9, 0xF8, 0x90, 0x47, 0xAD, 0xF5, 0xEB, 0x96, + 0x6D, 0xF1, 0x1C, 0xE0, 0xDC, 0x74, 0x1C, 0xE6, 0x2E, 0xE1, 0x76, 0x9D, 0xEE, + 0xF4, 0xEF, 0xA5, 0x31, 0x03, 0x87, 0x0E, 0x2C, 0x84, 0xA5, 0xF1, 0x22, 0xBE, + 0x48, 0xA9, 0xCD, 0x09, 0x07, 0xC1, 0xF0, 0xD4, 0xE7, 0x03, 0x82, 0x39, 0xE2, + 0xA0, 0x0B, 0xDE, 0xAC, 0x37, 0xAC, 0x62, 0x97, 0x8E, 0x79, 0xCE, 0x52, 0x24, + 0x78, 0xF9, 0x17, 0xD2, 0xF1, 0x5D, 0x2D, 0xA1, 0xDF, 0x12, 0x2C, 0x83, 0xE5, + 0x1A, 0x28, 0x9A, 0x2D, 0xED, 0x8A, 0xBF, 0xFC, 0x41, 0xC3, 0xEB, 0x0E, 0x91, + 0xDB, 0xF2, 0xA1, 0xC8, 0xA8, 0x01, 0x8B, 0xF2, 0xF3, 0x59, 0xB7, 0xA7, 0x6F, + 0x80, 0xFF, 0x0B, 0x46, 0xE1, 0x63, 0xA7, 0x5F, 0x6B, 0xBE, 0x33, 0x71, 0xBE, + 0x3A, 0xAF, 0xA9, 0x53, 0x5D, 0x3B, 0xB2, 0xF6, 0xEB, 0x42, 0x1C, 0x3E, 0x3F, + 0x1D, 0x6A, 0x34, 0xAE, 0xB1, 0x05, 0xA1, 0x32, 0x6C, 0xB5, 0xE4, 0xD3, 0xBB, + 0xE8, 0x10, 0x14, 0x9E, 0x68, 0x6A, 0x24, 0x51, 0xA5, 0x66, 0x64, 0xCC, 0xC4, + 0x2D, 0x96, 0xA2, 0xC7, 0x2D, 0x1F, 0x0A, 0x0F, 0x6B, 0xD9, 0xAD, 0xA3, 0x11, + 0x8F, 0x00, 0xAA, 0x06, 0xC2, 0x1E, 0xF3, 0xE8, 0x5A, 0x37, 0x4C, 0xD6, 0x4B, + 0x6B, 0x01, 0xC9, 0xB0, 0xB6, 0xB9, 0x92, 0xED, 0x1D, 0x08, 0xB0, 0x80, 0x06, + 0x20, 0xEA, 0xEE, 0xF9, 0x1D, 0xA4, 0x57, 0x73, 0x2E, 0x1B, 0xA5, 0xAF, 0xF6, + 0xAF, 0xAE, 0x04, 0x7C, 0x4C, 0x7E, 0xC8, 0xDB, 0xC0, 0xFB, 0x37, 0xC8, 0x7E, + 0xFE, 0x47, 0x0A, 0x3C, 0xFA, 0x61, 0xE7, 0xEB, 0x1B, 0xF3, 0x7C, 0x32, 0xE3, + 0x7C, 0x37, 0x66, 0x7C, 0x53, 0x07, 0xC2, 0x37, 0xA3, 0xBD, 0xF7, 0xFA, 0xE3, + 0x8A, 0x76, 0xCB, 0x6C, 0xC8, 0x13, 0xC4, 0x53, 0x53, 0xDB, 0xAD, 0x37, 0x1A, + 0xEB, 0xE0 +}; + +TEST_F(H264BitstreamConverterTest, Conversion_Success) { + // Initialize converter. + scoped_array<uint8> output; + H264BitstreamConverter converter; + + // Parse the headers. + uint32 config_size = converter.ParseConfigurationAndCalculateSize( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4)); + EXPECT_GT(config_size, 0U); + + // Go on with converting the headers. + output.reset(new uint8[config_size]); + EXPECT_TRUE(output.get() != NULL); + EXPECT_TRUE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4), + output.get(), + &config_size)); + + // Calculate buffer size for actual NAL unit. + uint32 output_size = converter.CalculateNeededOutputBufferSize( + kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + EXPECT_GT(output_size, 0U); + output_size += config_size; + output.reset(new uint8[output_size]); + EXPECT_TRUE(output.get() != NULL); + + uint32 output_size_left_for_nal_unit = output_size - config_size; + // Do the conversion for actual NAL unit. + EXPECT_TRUE(converter.ConvertNalUnitStreamToByteStream( + kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4), + output.get() + config_size, + &output_size_left_for_nal_unit)); + + // Classes allocated in stack are automatically destroyed. +} + +TEST_F(H264BitstreamConverterTest, Conversion_FailureNullData) { + // Initialize converter. + H264BitstreamConverter converter; + + // Simulate situation where there is no header data. + uint32 config_size = converter.ParseConfigurationAndCalculateSize(NULL, 0); + EXPECT_EQ(config_size, 0U); + + // Go on with converting the headers with NULL parameters. + EXPECT_FALSE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + NULL, + 0, + NULL, + &config_size)); + + // Simulate NULL parameters for buffer calculation. + uint32 output_size = converter.CalculateNeededOutputBufferSize(NULL, 0); + EXPECT_EQ(output_size, 0U); + + // Do the conversion for actual NAL unit with NULL paramaters. + EXPECT_FALSE(converter.ConvertNalUnitStreamToByteStream(NULL, + 0, + NULL, + &output_size)); + + // Classes allocated in stack are automatically destroyed. +} + +TEST_F(H264BitstreamConverterTest, Conversion_FailureHeaderBufferOverflow) { + // Initialize converter + H264BitstreamConverter converter; + + // Simulate 10 sps AVCDecoderConfigurationRecord, + // which would extend beyond the buffer. + uint8 corrupted_header[sizeof(kHeaderDataOkWithFieldLen4)]; + memcpy(corrupted_header, kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4)); + // 6th byte, 5 LSBs contain the number of sps's. + corrupted_header[5] = corrupted_header[5] | 0xA; + + // Parse the headers + uint32 config_size = converter.ParseConfigurationAndCalculateSize( + corrupted_header, + sizeof(corrupted_header)); + EXPECT_EQ(config_size, 0U); // Failure as a result of buffer overflows. + + // Classes allocated in stack are automatically destroyed. +} + +TEST_F(H264BitstreamConverterTest, Conversion_FailureNalUnitBreakage) { + // Initialize converter. + scoped_array<uint8> output; + H264BitstreamConverter converter; + + // Parse the headers. + uint32 config_size = converter.ParseConfigurationAndCalculateSize( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4)); + EXPECT_GT(config_size, 0U); + + // Go on with converting the headers. + output.reset(new uint8[config_size]); + EXPECT_TRUE(output.get() != NULL); + EXPECT_TRUE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4), + output.get(), + &config_size)); + + // Simulate NAL unit broken in middle by writing only some of the data. + uint8 corrupted_nal_unit[sizeof(kPacketDataOkWithFieldLen4) - 100]; + memcpy(corrupted_nal_unit, kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4) - 100); + + // Calculate buffer size for actual NAL unit, should return 0 because of + // incomplete input buffer. + uint32 output_size = converter.CalculateNeededOutputBufferSize( + corrupted_nal_unit, + sizeof(corrupted_nal_unit)); + EXPECT_EQ(output_size, 0U); + + // Ignore the error and try to go on with conversion simulating wrong usage. + output_size = sizeof(kPacketDataOkWithFieldLen4) + config_size; + output.reset(new uint8[output_size]); + EXPECT_TRUE(output.get() != NULL); + + uint32 output_size_left_for_nal_unit = output_size - config_size; + // Do the conversion for actual NAL unit, expecting failure. + EXPECT_FALSE(converter.ConvertNalUnitStreamToByteStream( + corrupted_nal_unit, + sizeof(corrupted_nal_unit), + output.get() + config_size, + &output_size_left_for_nal_unit)); + EXPECT_EQ(output_size_left_for_nal_unit, 0U); + + // Classes allocated in stack are automatically destroyed. +} + +TEST_F(H264BitstreamConverterTest, Conversion_FailureTooSmallOutputBuffer) { + // Initialize converter. + scoped_array<uint8> output; + H264BitstreamConverter converter; + + // Parse the headers. + uint32 config_size = converter.ParseConfigurationAndCalculateSize( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4)); + EXPECT_GT(config_size, 0U); + uint32 real_config_size = config_size; + + // Go on with converting the headers with too small buffer. + config_size -= 10; + output.reset(new uint8[config_size]); + EXPECT_TRUE(output.get() != NULL); + EXPECT_FALSE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4), + output.get(), + &config_size)); + EXPECT_EQ(config_size, 0U); + + // Still too small (but only 1 byte short). + config_size = real_config_size - 1; + output.reset(new uint8[config_size]); + EXPECT_TRUE(output.get() != NULL); + EXPECT_FALSE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4), + output.get(), + &config_size)); + EXPECT_EQ(config_size, 0U); + + // Finally, retry with valid buffer. + config_size = real_config_size; + output.reset(new uint8[config_size]); + EXPECT_TRUE(output.get() != NULL); + EXPECT_TRUE(converter.ConvertAVCDecoderConfigurationRecordToByteStream( + kHeaderDataOkWithFieldLen4, + sizeof(kHeaderDataOkWithFieldLen4), + output.get(), + &config_size)); + + // Calculate buffer size for actual NAL unit. + uint32 output_size = converter.CalculateNeededOutputBufferSize( + kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + EXPECT_GT(output_size, 0U); + output_size += config_size; + // Simulate too small output buffer. + output_size -= 1; + output.reset(new uint8[output_size]); + EXPECT_TRUE(output.get() != NULL); + + uint32 output_size_left_for_nal_unit = output_size - config_size; + // Do the conversion for actual NAL unit (expect failure). + EXPECT_FALSE(converter.ConvertNalUnitStreamToByteStream( + kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4), + output.get() + config_size, + &output_size_left_for_nal_unit)); + EXPECT_EQ(output_size_left_for_nal_unit, 0U); + + // Classes allocated in stack are automatically destroyed. +} + +} // namespace media + diff --git a/media/filters/bitstream_converter.h b/media/filters/bitstream_converter.h index f19e3f2..a1ca3c6 100644 --- a/media/filters/bitstream_converter.h +++ b/media/filters/bitstream_converter.h @@ -27,9 +27,14 @@ class BitstreamConverter { BitstreamConverter() {} virtual ~BitstreamConverter() {} - // Attemps to convert the AVPacket from one format to another, based on the - // specific type of BitstreamConverter that was instantiated. + // Initialize does any preparations needed before doing the actual + // conversion. virtual bool Initialize() = 0; + + // Attemps to convert the AVPacket from one format to another, based on the + // specific type of BitstreamConverter that was instantiated. Output will be + // stored into the |packet|, but user should be aware that conversion can free + // and reallocate the input buffer, if it needs to do so to fit it in. virtual bool ConvertPacket(AVPacket* packet) = 0; private: diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 413ff5a..d482c83 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -17,6 +17,7 @@ #include "media/filters/bitstream_converter.h" #include "media/filters/ffmpeg_demuxer.h" #include "media/filters/ffmpeg_glue.h" +#include "media/filters/ffmpeg_h264_bitstream_converter.h" namespace media { @@ -208,7 +209,13 @@ void FFmpegDemuxerStream::EnableBitstreamConverter() { const char* filter_name = NULL; if (stream_->codec->codec_id == CODEC_ID_H264) { filter_name = "h264_mp4toannexb"; - } else if (stream_->codec->codec_id == CODEC_ID_MPEG4) { + // Use Chromium bitstream converter in case of H.264 + bitstream_converter_.reset( + new FFmpegH264BitstreamConverter(stream_->codec)); + CHECK(bitstream_converter_->Initialize()); + return; + } + if (stream_->codec->codec_id == CODEC_ID_MPEG4) { filter_name = "mpeg4video_es"; } else if (stream_->codec->codec_id == CODEC_ID_WMV3) { filter_name = "vc1_asftorcv"; diff --git a/media/filters/ffmpeg_h264_bitstream_converter.cc b/media/filters/ffmpeg_h264_bitstream_converter.cc new file mode 100644 index 0000000..6220daf --- /dev/null +++ b/media/filters/ffmpeg_h264_bitstream_converter.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2011 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/filters/ffmpeg_h264_bitstream_converter.h" + +#include "base/logging.h" +#include "media/ffmpeg/ffmpeg_common.h" + +namespace media { + +FFmpegH264BitstreamConverter::FFmpegH264BitstreamConverter( + AVCodecContext* stream_context) + : configuration_processed_(false), + stream_context_(stream_context) { + CHECK(stream_context_); +} + +FFmpegH264BitstreamConverter::~FFmpegH264BitstreamConverter() {} + +bool FFmpegH264BitstreamConverter::Initialize() { + return true; +} + +bool FFmpegH264BitstreamConverter::ConvertPacket(AVPacket* packet) { + uint32 output_packet_size = 0; + uint32 configuration_size = 0; + uint32 io_size = 0; + if (packet == NULL) { + return false; + } + + // Calculate the needed output buffer size. + if (!configuration_processed_) { + // FFmpeg's AVCodecContext's extradata field contains the Decoder + // Specific Information from MP4 headers that contain the H.264 SPS and + // PPS members. See ISO/IEC 14496-15 Chapter 5.2.4 + // AVCDecoderConfigurationRecord for exact specification. + // Extradata must be at least 7 bytes long. + if (stream_context_->extradata == NULL || + stream_context_->extradata_size <= 7) { + return false; // Can't go on with conversion without configuration. + } + configuration_size += converter_.ParseConfigurationAndCalculateSize( + stream_context_->extradata, + stream_context_->extradata_size); + if (configuration_size == 0) { + return false; // Not possible to parse the configuration. + } + } + uint32 output_nal_size = + converter_.CalculateNeededOutputBufferSize(packet->data, packet->size); + if (output_nal_size == 0) { + return false; // Invalid input packet. + } + output_packet_size = configuration_size + output_nal_size; + + // Allocate new packet for the output. + AVPacket dest_packet; + if (av_new_packet(&dest_packet, output_packet_size) != 0) { + return false; // Memory allocation failure. + } + // This is a bit tricky: since the interface does not allow us to replace + // the pointer of the old packet with a new one, we will initially copy the + // metadata from old packet to new bigger packet. + dest_packet.pts = packet->pts; + dest_packet.dts = packet->dts; + dest_packet.pos = packet->pos; + dest_packet.duration = packet->duration; + dest_packet.convergence_duration = packet->convergence_duration; + dest_packet.flags = packet->flags; + dest_packet.stream_index = packet->stream_index; + + // Process the configuration if not done earlier. + if (!configuration_processed_) { + if (!converter_.ConvertAVCDecoderConfigurationRecordToByteStream( + stream_context_->extradata, stream_context_->extradata_size, + dest_packet.data, &configuration_size)) { + return false; // Failed to convert the buffer. + } + configuration_processed_ = true; + } + + // Proceed with the conversion of the actual in-band NAL units, leave room + // for configuration in the beginning. + io_size = dest_packet.size - configuration_size; + if (!converter_.ConvertNalUnitStreamToByteStream( + packet->data, packet->size, + dest_packet.data + configuration_size, &io_size)) { + return false; + } + + // At the end we must destroy the old packet. + packet->destruct(packet); + *packet = dest_packet; // Finally, replace the values in the input packet. + + return true; +} + +} // namespace media + diff --git a/media/filters/ffmpeg_h264_bitstream_converter.h b/media/filters/ffmpeg_h264_bitstream_converter.h new file mode 100644 index 0000000..69d8e4c --- /dev/null +++ b/media/filters/ffmpeg_h264_bitstream_converter.h @@ -0,0 +1,67 @@ +// Copyright (c) 2011 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_FILTERS_FFMPEG_H264_BITSTREAM_CONVERTER_H_ +#define MEDIA_FILTERS_FFMPEG_H264_BITSTREAM_CONVERTER_H_ + +#include "base/basictypes.h" +#include "media/base/h264_bitstream_converter.h" +#include "media/filters/bitstream_converter.h" + +// Forward declarations for FFmpeg datatypes used. +struct AVCodecContext; +struct AVPacket; + +namespace media { + +// FFmpegH264BitstreamConverter does the conversion on single NAL unit +// basis which is contained within the AVPacket given to ConvertPacket() member +// function with the exception of the first packet which is prepended with the +// AVC decoder configuration record information. For example: +// +// NAL unit #1 ==> bytestream buffer #1 (AVC configuraion + NAL unit #1) +// NAL unit #2 ==> bytestream buffer #2 (NAL unit #2) +// ... +// NAL unit #n ==> bytestream buffer #n (NAL unit #n) +// +// User of the object can append output into one bigger buffer by the client if +// efficiency reasons warrants the client to do so. +// +// FFmpegH264BitstreamConverter acts as an adapter for the H264 Bitstream +// converter class by implementing the BitstreamConverter interface expected +// by media pipeline streams demuxed by FFmpegDemuxer. +// +// FFmpegH264BitstreamConverter uses FFmpeg allocation methods for buffer +// allocation to ensure compatibility with FFmpeg's memory management. + +class FFmpegH264BitstreamConverter : public BitstreamConverter { + public: + // The |stream_context| will be used during conversion and should be the + // AVCodecContext for the stream sourcing these packets. A reference to + // |stream_context| is retained, so it must outlive this class. + explicit FFmpegH264BitstreamConverter(AVCodecContext* stream_context); + virtual ~FFmpegH264BitstreamConverter(); + + // BitstreamConverter implementation + virtual bool Initialize(); + virtual bool ConvertPacket(AVPacket* packet); + + private: + // Actual converter class. + H264BitstreamConverter converter_; + + // Flag for indicating whether global parameter sets have been processed. + bool configuration_processed_; + + // Variable to hold a pointer to memory where we can access the global + // data from the FFmpeg file format's global headers. + AVCodecContext* stream_context_; + + DISALLOW_COPY_AND_ASSIGN(FFmpegH264BitstreamConverter); +}; + +} // namespace media + +#endif // MEDIA_FILTERS_FFMPEG_H264_BITSTREAM_CONVERTER_H_ + diff --git a/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc b/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc new file mode 100644 index 0000000..bf582f6 --- /dev/null +++ b/media/filters/ffmpeg_h264_bitstream_converter_unittest.cc @@ -0,0 +1,443 @@ +// Copyright (c) 2011 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/base/mock_ffmpeg.h" +#include "media/filters/ffmpeg_h264_bitstream_converter.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrictMock; + +namespace media { + +// Forward declarations for fake FFmpeg packet handling functions. +static void fake_av_destruct_packet(AVPacket* pkt); +static void fake_av_init_packet(AVPacket* pkt); +static int fake_av_new_packet(AVPacket* pkt, int size); + +// Test data arrays. +static const uint8 kHeaderDataOkWithFieldLen4[] = { + 0x01, 0x42, 0x00, 0x28, 0xFF, 0xE1, 0x00, 0x08, 0x67, 0x42, 0x00, 0x28, + 0xE9, 0x05, 0x89, 0xC8, 0x01, 0x00, 0x04, 0x68, 0xCE, 0x06, 0xF2, 0x00 +}; + +static const uint8 kPacketDataOkWithFieldLen4[] = { + 0x00, 0x00, 0x0B, 0xF7, 0x65, 0xB8, 0x40, 0x57, 0x0B, 0xF0, + 0xDF, 0xF8, 0x00, 0x1F, 0x78, 0x98, 0x54, 0xAC, 0xF2, 0x00, 0x04, 0x9D, 0x26, + 0xE0, 0x3B, 0x5C, 0x00, 0x0A, 0x00, 0x8F, 0x9E, 0x86, 0x63, 0x1B, 0x46, 0xE7, + 0xD6, 0x45, 0x88, 0x88, 0xEA, 0x10, 0x89, 0x79, 0x01, 0x34, 0x30, 0x01, 0x8E, + 0x7D, 0x1A, 0x39, 0x45, 0x4E, 0x69, 0x86, 0x12, 0xF2, 0xE7, 0xCF, 0x50, 0xF8, + 0x26, 0x54, 0x17, 0xBE, 0x3F, 0xC4, 0x80, 0x32, 0xD8, 0x02, 0x32, 0xE4, 0xAE, + 0xDD, 0x39, 0x11, 0x8E, 0x54, 0x42, 0xAE, 0xBD, 0x12, 0xA4, 0xCE, 0xE2, 0x98, + 0x91, 0x05, 0xC4, 0xA8, 0x20, 0xC7, 0xB3, 0xD9, 0x47, 0x73, 0x09, 0xD5, 0xCF, + 0x62, 0x57, 0x3F, 0xFF, 0xFD, 0xB9, 0x94, 0x2B, 0x3D, 0x12, 0x1A, 0x84, 0x0B, + 0x28, 0xAD, 0x5C, 0x9E, 0x5C, 0xC3, 0xBB, 0xBD, 0x7F, 0xFE, 0x09, 0x87, 0x74, + 0x39, 0x1C, 0xA5, 0x0E, 0x44, 0xD8, 0x5D, 0x41, 0xDB, 0xAA, 0xBC, 0x05, 0x16, + 0xA3, 0x98, 0xEE, 0xEE, 0x9C, 0xA0, 0xF1, 0x23, 0x90, 0xF0, 0x5E, 0x9F, 0xF4, + 0xFA, 0x7F, 0x4B, 0x69, 0x66, 0x49, 0x52, 0xDD, 0xD6, 0xC0, 0x0F, 0x8C, 0x6E, + 0x80, 0xDD, 0x7A, 0xDF, 0x10, 0xCD, 0x4B, 0x54, 0x6F, 0xFC, 0x7D, 0x34, 0xBA, + 0x8B, 0xD4, 0xD9, 0x30, 0x18, 0x9F, 0x39, 0x04, 0x9F, 0xCB, 0xDB, 0x1B, 0xA7, + 0x70, 0x96, 0xAF, 0xFF, 0x6F, 0xB5, 0xBF, 0x58, 0x01, 0x98, 0xCD, 0xF2, 0x66, + 0x28, 0x1A, 0xC4, 0x9E, 0x58, 0x40, 0x39, 0xAE, 0x07, 0x11, 0x3F, 0xF2, 0x9B, + 0x06, 0x9C, 0xB8, 0xC9, 0x16, 0x12, 0x09, 0x8E, 0xD2, 0xD4, 0xF5, 0xC6, 0x77, + 0x40, 0x0F, 0xFD, 0x12, 0x19, 0x55, 0x1A, 0x8E, 0x9C, 0x18, 0x8B, 0x0D, 0x18, + 0xFA, 0xBA, 0x7F, 0xBB, 0x83, 0xBB, 0x85, 0xA0, 0xCC, 0xAF, 0xF6, 0xEA, 0x81, + 0x10, 0x18, 0x8E, 0x10, 0x00, 0xCB, 0x7F, 0x27, 0x08, 0x06, 0xDE, 0x3C, 0x20, + 0xE5, 0xFE, 0xCC, 0x4F, 0xB3, 0x41, 0xE0, 0xCC, 0x4C, 0x26, 0xC1, 0xC0, 0x2C, + 0x16, 0x12, 0xAA, 0x04, 0x83, 0x51, 0x4E, 0xCA, 0x00, 0xCF, 0x42, 0x9C, 0x06, + 0x2D, 0x06, 0xDD, 0x1D, 0x08, 0x75, 0xE0, 0x89, 0xC7, 0x62, 0x68, 0x2E, 0xBF, + 0x4D, 0x2D, 0x0A, 0xC4, 0x86, 0xF6, 0x2F, 0xA1, 0x49, 0xA7, 0x0F, 0xDB, 0x1F, + 0x82, 0xEC, 0xC1, 0x62, 0xFB, 0x7F, 0xF1, 0xAE, 0xA6, 0x1A, 0xD5, 0x6B, 0x06, + 0x5E, 0xB6, 0x02, 0x50, 0xAE, 0x2D, 0xF9, 0xD9, 0x95, 0xAD, 0x01, 0x8C, 0x53, + 0x01, 0xAF, 0xCE, 0xE5, 0xA5, 0xBB, 0x95, 0x8A, 0x85, 0x70, 0x77, 0xE3, 0x9A, + 0x68, 0x1B, 0xDF, 0x47, 0xF9, 0xF4, 0xBD, 0x80, 0x7D, 0x76, 0x9A, 0x69, 0xFC, + 0xBE, 0x14, 0x0D, 0x87, 0x09, 0x12, 0x98, 0x20, 0x05, 0x46, 0xB7, 0xAE, 0x10, + 0xB7, 0x01, 0xB7, 0xDE, 0x3B, 0xDD, 0x7A, 0x8A, 0x55, 0x73, 0xAD, 0xDF, 0x69, + 0xDE, 0xD0, 0x51, 0x97, 0xA0, 0xE6, 0x5E, 0xBA, 0xBA, 0x80, 0x0F, 0x4E, 0x9A, + 0x68, 0x36, 0xE6, 0x9F, 0x5B, 0x39, 0xC0, 0x90, 0xA1, 0xC0, 0xC3, 0x82, 0xE4, + 0x50, 0xEA, 0x60, 0x7A, 0xDD, 0x5F, 0x8B, 0x5F, 0xAF, 0xFC, 0x74, 0xAF, 0xDC, + 0x56, 0xF7, 0x2E, 0x3E, 0x97, 0x6E, 0x2B, 0xF3, 0xAF, 0xFE, 0x7D, 0x32, 0xDC, + 0x56, 0xF8, 0xAF, 0xB5, 0xA3, 0xBB, 0x00, 0x5B, 0x84, 0x3D, 0x9F, 0x0B, 0x40, + 0x88, 0x61, 0x5F, 0x4F, 0x4F, 0xB0, 0xB3, 0x07, 0x81, 0x3E, 0xF2, 0xFB, 0x50, + 0xCA, 0x77, 0x40, 0x12, 0xA8, 0xE6, 0x11, 0x8E, 0xD6, 0x8A, 0xC6, 0xD6, 0x8C, + 0x1D, 0x63, 0x55, 0x3D, 0x34, 0xEA, 0xC3, 0xC6, 0x6A, 0xD2, 0x8C, 0xB0, 0x1D, + 0x5E, 0x4A, 0x7A, 0x8B, 0xD5, 0x99, 0x80, 0x84, 0x32, 0xFB, 0xB7, 0x02, 0x6E, + 0x61, 0xFE, 0xAC, 0x1B, 0x5D, 0x10, 0x23, 0x24, 0xC3, 0x8C, 0x7B, 0x58, 0x2C, + 0x4D, 0x04, 0x74, 0x84, 0x25, 0x10, 0x4E, 0x94, 0x29, 0x4D, 0x88, 0xAE, 0x65, + 0x53, 0xB9, 0x95, 0x4E, 0xE7, 0xDD, 0xEE, 0xF2, 0x70, 0x1F, 0x26, 0x4F, 0xA8, + 0xBC, 0x3D, 0x35, 0x02, 0x3B, 0xC0, 0x98, 0x70, 0x38, 0x18, 0xE5, 0x1E, 0x05, + 0xAC, 0x28, 0xAA, 0x46, 0x1A, 0xB0, 0x19, 0x99, 0x18, 0x35, 0x78, 0x1E, 0x41, + 0x60, 0x0D, 0x4F, 0x7E, 0xEC, 0x37, 0xC3, 0x30, 0x73, 0x2A, 0x69, 0xFE, 0xEF, + 0x27, 0xEE, 0x13, 0xCC, 0xD0, 0xDB, 0xE6, 0x45, 0xEC, 0x5C, 0xB5, 0x71, 0x54, + 0x2E, 0xB1, 0xE9, 0x88, 0xB4, 0x3F, 0x6F, 0xFD, 0xF7, 0xFF, 0x9D, 0x2D, 0x52, + 0x2E, 0xAE, 0xC9, 0x95, 0xDE, 0xBF, 0xDF, 0xFF, 0xBF, 0x21, 0xB3, 0x2B, 0xF5, + 0xF7, 0xF7, 0xD1, 0xA0, 0xF0, 0x76, 0x68, 0x37, 0xDB, 0x8F, 0x85, 0x4D, 0xA8, + 0x1A, 0xF9, 0x7F, 0x75, 0xA7, 0x93, 0xF5, 0x03, 0xC1, 0xF2, 0x60, 0x8A, 0x92, + 0x53, 0xF5, 0xD1, 0xC1, 0x56, 0x4B, 0x68, 0x05, 0x16, 0x88, 0x61, 0xE7, 0x14, + 0xC8, 0x0D, 0xF0, 0xDF, 0xEF, 0x46, 0x4A, 0xED, 0x0B, 0xD1, 0xD1, 0xD1, 0xA4, + 0x85, 0xA3, 0x2C, 0x1D, 0xDE, 0x45, 0x14, 0xA1, 0x8E, 0xA8, 0xD9, 0x8C, 0xAB, + 0x47, 0x31, 0xF1, 0x00, 0x15, 0xAD, 0x80, 0x20, 0xAA, 0xE4, 0x57, 0xF8, 0x05, + 0x14, 0x58, 0x0B, 0xD3, 0x63, 0x00, 0x8F, 0x44, 0x15, 0x7F, 0x19, 0xC7, 0x0A, + 0xE0, 0x49, 0x32, 0xFE, 0x36, 0x0E, 0xF3, 0x66, 0x10, 0x2B, 0x11, 0x73, 0x3D, + 0x19, 0x92, 0x22, 0x20, 0x75, 0x1F, 0xF1, 0xDB, 0x96, 0x73, 0xCF, 0x1B, 0x53, + 0xFF, 0xD2, 0x23, 0xF2, 0xB6, 0xAA, 0xB6, 0x44, 0xA3, 0x73, 0x7E, 0x00, 0x2D, + 0x4D, 0x4D, 0x87, 0xE0, 0x84, 0x55, 0xD6, 0x03, 0xB8, 0xD8, 0x90, 0xEF, 0xC0, + 0x76, 0x5D, 0x69, 0x02, 0x00, 0x0E, 0x17, 0xD0, 0x02, 0x96, 0x50, 0xEA, 0xAB, + 0xBF, 0x0D, 0xAF, 0xCB, 0xD3, 0xFF, 0xAA, 0x9D, 0x7F, 0xD6, 0xBD, 0x2C, 0x14, + 0xB4, 0xCD, 0x20, 0x73, 0xB4, 0xF4, 0x38, 0x96, 0xDE, 0xB0, 0x6B, 0xE5, 0x1B, + 0xFD, 0x0E, 0x0B, 0xA4, 0x81, 0xBF, 0xC8, 0xA0, 0x21, 0x76, 0x7B, 0x25, 0x3F, + 0xE6, 0x84, 0x40, 0x1A, 0xDA, 0x25, 0x5A, 0xFF, 0x73, 0x6B, 0x14, 0x1B, 0xF7, + 0x08, 0xFA, 0x26, 0x73, 0x7A, 0x58, 0x02, 0x1A, 0xE6, 0x63, 0xB6, 0x45, 0x7B, + 0xE3, 0xE0, 0x80, 0x14, 0x42, 0xA8, 0x7D, 0xF3, 0x80, 0x9B, 0x01, 0x43, 0x82, + 0x82, 0x8C, 0xBE, 0x0D, 0xFD, 0xAE, 0x88, 0xA8, 0xB9, 0xC3, 0xEE, 0xFF, 0x46, + 0x00, 0x84, 0xE6, 0xB4, 0x0C, 0xA9, 0x66, 0xC6, 0x74, 0x72, 0xAA, 0xA4, 0x3A, + 0xB0, 0x1B, 0x06, 0xB4, 0xDB, 0xE8, 0xC2, 0x17, 0xA2, 0xBC, 0xBE, 0x5C, 0x0F, + 0x2A, 0x76, 0xD5, 0xEE, 0x39, 0x36, 0x7C, 0x25, 0x94, 0x15, 0x3C, 0xC9, 0xB9, + 0x93, 0x07, 0x19, 0xAF, 0xE6, 0x70, 0xC3, 0xF5, 0xD4, 0x17, 0x87, 0x57, 0x77, + 0x7D, 0xCF, 0x0D, 0xDD, 0xDE, 0xB7, 0xFF, 0xB4, 0xDA, 0x20, 0x45, 0x1A, 0x45, + 0xF4, 0x58, 0x01, 0xBC, 0xEB, 0x3F, 0x16, 0x7F, 0x4C, 0x15, 0x84, 0x8C, 0xE5, + 0xF6, 0x96, 0xA6, 0xA1, 0xB9, 0xB2, 0x7F, 0x6B, 0xFF, 0x31, 0xF2, 0xF5, 0xC9, + 0xFF, 0x61, 0xEE, 0xB5, 0x84, 0xAE, 0x68, 0x41, 0xEA, 0xD0, 0xF0, 0xA5, 0xCE, + 0x0C, 0xE6, 0x4C, 0x6D, 0x6D, 0x94, 0x08, 0xC9, 0xA9, 0x4A, 0x60, 0x6D, 0x01, + 0x3B, 0xEF, 0x4D, 0x99, 0x8D, 0x42, 0x2A, 0x6B, 0x8A, 0xC7, 0xFA, 0xA9, 0x90, + 0x40, 0x00, 0x90, 0xF3, 0xA0, 0x75, 0x8E, 0xD5, 0xFE, 0xE7, 0xBD, 0x02, 0x87, + 0x0C, 0x7D, 0xF0, 0xAF, 0x1E, 0x5F, 0x8D, 0xC8, 0xE1, 0xD4, 0x56, 0x08, 0xBF, + 0x76, 0x80, 0xD4, 0x18, 0x89, 0x2D, 0x57, 0xDF, 0x66, 0xD0, 0x46, 0x68, 0x77, + 0x55, 0x47, 0xF5, 0x7C, 0xF7, 0xA6, 0x66, 0xD6, 0x5A, 0x64, 0x55, 0xD4, 0x80, + 0xC4, 0x55, 0xE9, 0x36, 0x3F, 0x5E, 0xE2, 0x5C, 0x7F, 0x5F, 0xCE, 0x7F, 0xE1, + 0x0C, 0x82, 0x3D, 0x6B, 0x6E, 0xA2, 0xEA, 0x3B, 0x1F, 0xE8, 0x9E, 0xC7, 0x4E, + 0x24, 0x3D, 0xDD, 0xFA, 0xEB, 0x71, 0xDF, 0xFE, 0x15, 0xFE, 0x41, 0x9B, 0xB4, + 0x4E, 0xAB, 0x51, 0xE5, 0x1F, 0x7D, 0x2D, 0xAC, 0xD0, 0x66, 0xD9, 0xA1, 0x59, + 0x78, 0xC6, 0xEF, 0xC4, 0x43, 0x08, 0x65, 0x18, 0x73, 0xDE, 0x2A, 0xAD, 0x72, + 0xE7, 0x5A, 0x7E, 0x33, 0x04, 0x72, 0x38, 0x57, 0x47, 0x73, 0x10, 0x1D, 0x88, + 0x57, 0x4C, 0xDF, 0xA7, 0x78, 0x16, 0xFB, 0x01, 0x21, 0x28, 0x2D, 0xB6, 0x7E, + 0x05, 0x18, 0x32, 0x52, 0xC3, 0x49, 0x0B, 0x32, 0x18, 0x12, 0x93, 0x54, 0x15, + 0x3B, 0xC8, 0x6D, 0x4A, 0x77, 0xEF, 0x0A, 0x46, 0x83, 0x89, 0x5C, 0x8B, 0xCB, + 0x18, 0xA6, 0xDC, 0x97, 0x6F, 0xEE, 0xEE, 0x00, 0x6A, 0xF1, 0x10, 0xFE, 0x07, + 0x0C, 0xE0, 0x53, 0xD2, 0xB8, 0x45, 0xF4, 0x6E, 0x16, 0x4B, 0xC9, 0x9C, 0xC7, + 0x93, 0x83, 0x23, 0x1D, 0x4D, 0x00, 0xB9, 0x4F, 0x86, 0x51, 0xF0, 0x29, 0x69, + 0x41, 0x21, 0xC5, 0x4A, 0xC6, 0x6D, 0xD1, 0x81, 0x38, 0xDB, 0x7C, 0x06, 0xA8, + 0x26, 0x8E, 0x71, 0x00, 0x4C, 0x44, 0x14, 0x05, 0xF2, 0x1C, 0x00, 0x49, 0xFC, + 0x29, 0x6A, 0xF9, 0x9E, 0xD1, 0x35, 0x4B, 0xB7, 0xE5, 0xDB, 0xFC, 0x01, 0x04, + 0x3F, 0x70, 0x33, 0x56, 0x87, 0x69, 0x01, 0xB4, 0xCE, 0x1C, 0x4D, 0x2E, 0x83, + 0x51, 0x51, 0xD0, 0x37, 0x3B, 0xB4, 0xBA, 0x47, 0xF5, 0xFF, 0xBF, 0xFA, 0xD5, + 0x03, 0x65, 0xD3, 0x28, 0x9F, 0x38, 0x57, 0xFE, 0x71, 0xD8, 0x9C, 0x16, 0xEE, + 0x72, 0x19, 0x03, 0x17, 0x6E, 0xC0, 0xEC, 0x49, 0x3D, 0x96, 0xE2, 0x30, 0x97, + 0x97, 0x84, 0x38, 0x6B, 0xE8, 0x2E, 0xAB, 0x0E, 0x2E, 0x03, 0x52, 0xBA, 0x68, + 0x55, 0xBA, 0x1D, 0x2C, 0x47, 0xAA, 0x72, 0xAE, 0x02, 0x31, 0x6E, 0xA1, 0xDC, + 0xAD, 0x0F, 0x4A, 0x46, 0xC9, 0xF2, 0xA9, 0xAB, 0xFD, 0x87, 0x89, 0x5C, 0xB3, + 0x75, 0x7E, 0xE3, 0xDE, 0x9F, 0xC4, 0x02, 0x1E, 0xA2, 0xF8, 0x8B, 0xD3, 0x00, + 0x83, 0x96, 0xC4, 0xD0, 0xB9, 0x62, 0xB9, 0x69, 0xEC, 0x56, 0xDF, 0x7D, 0x91, + 0x4B, 0x68, 0x27, 0xA8, 0x61, 0x78, 0xA7, 0x95, 0x66, 0x51, 0x41, 0xF6, 0xCE, + 0x78, 0xD3, 0x9A, 0x91, 0xA0, 0x31, 0x09, 0x47, 0xB8, 0x47, 0xB8, 0x44, 0xE1, + 0x13, 0x86, 0x7E, 0x92, 0x80, 0xC6, 0x1A, 0xF7, 0x79, 0x7E, 0xF1, 0x5D, 0x9F, + 0x17, 0x2D, 0x80, 0x00, 0x79, 0x34, 0x7D, 0xE3, 0xAD, 0x60, 0x00, 0x20, 0x07, + 0x80, 0x00, 0x40, 0x01, 0xF8, 0xA1, 0x86, 0xB1, 0xEE, 0x21, 0x63, 0x85, 0x60, + 0x51, 0x84, 0x90, 0x7E, 0x92, 0x09, 0x39, 0x1C, 0x16, 0x87, 0x5C, 0xA6, 0x09, + 0x90, 0x06, 0x34, 0x6E, 0xB8, 0x8D, 0x5D, 0xAC, 0x77, 0x97, 0xB5, 0x4D, 0x30, + 0xFD, 0x39, 0xD0, 0x50, 0x00, 0xC9, 0x98, 0x04, 0x86, 0x00, 0x0D, 0xD8, 0x3E, + 0x34, 0xC2, 0xA6, 0x25, 0xF8, 0x20, 0xCC, 0x6D, 0x9E, 0x63, 0x05, 0x30, 0xC4, + 0xC6, 0xCC, 0x54, 0x31, 0x9F, 0x3C, 0xF5, 0x86, 0xB9, 0x08, 0x18, 0xC3, 0x1E, + 0xB9, 0xA0, 0x0C, 0x45, 0x2C, 0x54, 0x32, 0x8B, 0x85, 0x86, 0x59, 0xC3, 0xB3, + 0x50, 0x5A, 0xFE, 0xBA, 0xF7, 0x4D, 0xC9, 0x9C, 0x9E, 0x01, 0xDF, 0xD7, 0x6E, + 0xB5, 0x15, 0x53, 0x08, 0x57, 0xA4, 0x71, 0x36, 0x80, 0x46, 0x05, 0x21, 0x48, + 0x7B, 0x91, 0xC8, 0xAA, 0xFF, 0x07, 0x9F, 0x78, 0x68, 0xCF, 0x3C, 0xEF, 0xFF, + 0xBC, 0xB6, 0xA2, 0x36, 0xB7, 0x9F, 0x54, 0xF6, 0x6F, 0x5D, 0xDD, 0x75, 0xD4, + 0x3C, 0x75, 0xE8, 0xCF, 0x15, 0x02, 0x5B, 0x94, 0xC3, 0xA2, 0x41, 0x63, 0xA1, + 0x14, 0xF6, 0xC0, 0x57, 0x15, 0x9F, 0x0C, 0x3F, 0x80, 0xF2, 0x98, 0xEE, 0x41, + 0x85, 0xEE, 0xBC, 0xAA, 0xE9, 0x59, 0xAA, 0xA0, 0x92, 0xCA, 0x00, 0xF3, 0x50, + 0xCC, 0xFF, 0xAD, 0x97, 0x69, 0xA7, 0xF2, 0x0B, 0x8F, 0xD7, 0xD7, 0x82, 0x3A, + 0xBB, 0x98, 0x1D, 0xCB, 0x89, 0x0B, 0x9B, 0x05, 0xF7, 0xD0, 0x1A, 0x60, 0xF3, + 0x29, 0x16, 0x12, 0xF8, 0xF4, 0xF1, 0x4A, 0x05, 0x9B, 0x57, 0x12, 0x7E, 0x3A, + 0x4A, 0x8D, 0xA6, 0xDF, 0xB6, 0xDD, 0xDF, 0xC3, 0xF0, 0xD2, 0xD4, 0xD7, 0x41, + 0xA6, 0x00, 0x76, 0x8C, 0x75, 0x08, 0xF0, 0x19, 0xD8, 0x14, 0x63, 0x55, 0x52, + 0x18, 0x30, 0x98, 0xD0, 0x3F, 0x65, 0x52, 0xB3, 0x88, 0x6D, 0x17, 0x39, 0x93, + 0xCA, 0x3B, 0xB4, 0x1D, 0x8D, 0xDF, 0xDF, 0xAD, 0x72, 0xDA, 0x74, 0xAF, 0xBD, + 0x31, 0xF9, 0x12, 0x61, 0x45, 0x29, 0x4C, 0x2B, 0x61, 0xA1, 0x12, 0x90, 0x53, + 0xE7, 0x5A, 0x9D, 0x44, 0xC8, 0x3A, 0x83, 0xDC, 0x34, 0x4C, 0x07, 0xAF, 0xDB, + 0x90, 0xCD, 0x03, 0xA4, 0x64, 0x78, 0xBD, 0x55, 0xB2, 0x56, 0x59, 0x32, 0xAB, + 0x13, 0x2C, 0xC9, 0x77, 0xF8, 0x3B, 0xDF, 0xFF, 0xAC, 0x07, 0xB9, 0x08, 0x7B, + 0xE9, 0x82, 0xB9, 0x59, 0xC7, 0xFF, 0x86, 0x2C, 0x12, 0x7C, 0xC6, 0x65, 0x3C, + 0x71, 0xB8, 0x98, 0x9F, 0xA2, 0x45, 0x03, 0xA5, 0xD9, 0xC3, 0xCF, 0xFA, 0xEB, + 0x89, 0xAD, 0x03, 0xEE, 0xDD, 0x76, 0xD3, 0x4F, 0x10, 0x6F, 0xF0, 0xC1, 0x60, + 0x0C, 0x00, 0xD4, 0x76, 0x12, 0x0A, 0x8D, 0xDC, 0xFD, 0x5E, 0x0B, 0x26, 0x2F, + 0x01, 0x1D, 0xB9, 0xE7, 0x73, 0xD4, 0xF2, 0xCB, 0xD8, 0x78, 0x21, 0x52, 0x4B, + 0x83, 0x3C, 0x44, 0x72, 0x0E, 0xB1, 0x4E, 0x37, 0xBC, 0xC7, 0x50, 0xFA, 0x07, + 0x80, 0x71, 0x10, 0x0B, 0x24, 0xD1, 0x7E, 0xDA, 0x7F, 0xA7, 0x2F, 0x40, 0xAA, + 0xD3, 0xF5, 0x44, 0x10, 0x56, 0x4E, 0x3B, 0xF1, 0x6E, 0x9A, 0xA0, 0xEA, 0x85, + 0x66, 0x16, 0xFB, 0x5C, 0x0B, 0x2B, 0x74, 0x18, 0xAF, 0x3D, 0x04, 0x3E, 0xCE, + 0x88, 0x9B, 0x3E, 0xF4, 0xB9, 0x00, 0x60, 0x0E, 0xE1, 0xE2, 0xCB, 0x12, 0xB9, + 0x6D, 0x5A, 0xC7, 0x55, 0x1D, 0xB9, 0x79, 0xAC, 0x43, 0x43, 0xE6, 0x3B, 0xDD, + 0x7E, 0x9F, 0x78, 0xD3, 0xEA, 0xA3, 0x11, 0xFF, 0xDB, 0xBB, 0xB8, 0x97, 0x37, + 0x15, 0xDB, 0xF1, 0x97, 0x96, 0xC7, 0xFC, 0xE5, 0xBF, 0xF2, 0x86, 0xC0, 0xFA, + 0x9B, 0x4C, 0x00, 0x04, 0x03, 0xA5, 0xB6, 0xB7, 0x9C, 0xD9, 0xAB, 0x09, 0x77, + 0x51, 0x18, 0x3B, 0xAD, 0x61, 0x6C, 0xFC, 0x51, 0x96, 0xFB, 0x19, 0xC8, 0x52, + 0x35, 0x07, 0x00, 0x63, 0x87, 0x14, 0x04, 0xFA, 0x7A, 0x48, 0x3E, 0x00, 0x47, + 0x29, 0x07, 0x74, 0x97, 0x74, 0x84, 0xEB, 0xB2, 0x16, 0xB2, 0x31, 0x81, 0xCE, + 0x2A, 0x31, 0xA7, 0xB1, 0xEB, 0x83, 0x34, 0x7A, 0x73, 0xD7, 0x2F, 0xFF, 0xBC, + 0xFF, 0xE5, 0xAA, 0xF2, 0xB5, 0x6E, 0x9E, 0xA5, 0x70, 0x8A, 0x8C, 0xDF, 0x6A, + 0x06, 0x16, 0xC1, 0xAB, 0x59, 0x70, 0xD9, 0x3D, 0x47, 0x7C, 0xDD, 0xEF, 0xDF, + 0x2F, 0xFF, 0x42, 0x6B, 0xBA, 0x4B, 0xBF, 0xF8, 0x7F, 0xF2, 0x03, 0x0D, 0x79, + 0xBC, 0x03, 0x76, 0x64, 0x1C, 0x0D, 0x7B, 0xD7, 0xBD, 0xB0, 0x6C, 0xD8, 0x61, + 0x17, 0x17, 0x8C, 0xED, 0x4E, 0x20, 0xEB, 0x55, 0x33, 0x39, 0xE9, 0x7E, 0xBE, + 0x8E, 0x05, 0x4B, 0x78, 0x96, 0x85, 0xCC, 0x68, 0xC9, 0x78, 0xAF, 0xAE, 0x44, + 0x36, 0x61, 0xD3, 0x53, 0xEB, 0xB3, 0x3E, 0x4F, 0x97, 0xE2, 0x8D, 0xAE, 0x90, + 0xED, 0xB5, 0x4F, 0x8E, 0xE4, 0x7A, 0x44, 0xCF, 0x9D, 0xC5, 0x77, 0x4D, 0xAB, + 0x4F, 0xE5, 0xC5, 0x73, 0xA0, 0xC8, 0xA5, 0xBB, 0x4B, 0x7D, 0xD5, 0xFB, 0xFB, + 0xFF, 0x61, 0xFD, 0xAA, 0x1A, 0x62, 0x7E, 0x3C, 0x66, 0x34, 0x15, 0x64, 0x25, + 0xEC, 0x7C, 0x9D, 0x6A, 0x64, 0x4D, 0x80, 0xD5, 0x4F, 0xFE, 0x8E, 0xEE, 0x18, + 0x53, 0xC1, 0x09, 0x51, 0xF7, 0xC0, 0xA6, 0xB2, 0x9B, 0x19, 0x2B, 0x14, 0x66, + 0x66, 0x4B, 0x39, 0x62, 0x1D, 0x84, 0xB9, 0x02, 0x84, 0xAC, 0xC1, 0xDA, 0x6C, + 0x80, 0xCD, 0x40, 0x20, 0x20, 0x19, 0x51, 0xDC, 0x2B, 0x7D, 0x5D, 0x7F, 0xE3, + 0x86, 0x8E, 0xC3, 0x35, 0xFE, 0x5C, 0xF6, 0x1C, 0xFF, 0x05, 0x9E, 0xB5, 0xB6, + 0xBB, 0xBE, 0xF7, 0x2F, 0xB7, 0xE1, 0xF5, 0x33, 0x86, 0xA0, 0x47, 0xDE, 0xF7, + 0xE9, 0x3B, 0xBE, 0x7E, 0x9B, 0x17, 0xFC, 0xFD, 0x2E, 0x40, 0x86, 0x41, 0x75, + 0xF1, 0xB2, 0x18, 0xA9, 0xDE, 0x2D, 0xD6, 0x04, 0x20, 0xA4, 0xBA, 0x81, 0xBC, + 0x1D, 0x5A, 0xD6, 0xF7, 0xF6, 0xB8, 0x42, 0xF7, 0xF5, 0x3D, 0x97, 0xAC, 0xCD, + 0x6F, 0xAD, 0xDB, 0x4F, 0x5A, 0x2E, 0x64, 0xB9, 0x5D, 0xDD, 0x8B, 0x4A, 0x35, + 0x44, 0xFE, 0x3D, 0xC6, 0x77, 0x7A, 0xBF, 0xDA, 0xAC, 0x9E, 0xB0, 0xA2, 0xB9, + 0x6C, 0xAF, 0x02, 0xDD, 0xF2, 0x71, 0x2B, 0xEF, 0xD3, 0x51, 0x0E, 0x07, 0x11, + 0xBD, 0xED, 0x39, 0x7F, 0xD9, 0xB8, 0xBD, 0xEE, 0x35, 0xE9, 0x5C, 0x67, 0x42, + 0xDA, 0x05, 0x6E, 0x39, 0xCE, 0x55, 0xFB, 0x26, 0xB7, 0x90, 0x4B, 0xDA, 0x91, + 0x48, 0xFD, 0xDE, 0xB2, 0xEC, 0x88, 0x9A, 0x46, 0x1A, 0x4C, 0xD4, 0x05, 0x12, + 0x85, 0x57, 0x37, 0x22, 0xD3, 0x0E, 0x4F, 0x79, 0xE3, 0x81, 0xA9, 0x2B, 0x5F, + 0xD7, 0x6D, 0xBD, 0x21, 0x98, 0x6F, 0x7D, 0xF5, 0x32, 0x7A, 0x6E, 0xF8, 0x20, + 0x01, 0x50, 0x90, 0x7A, 0x88, 0x3E, 0x0D, 0x57, 0xB1, 0x58, 0x65, 0xE6, 0x82, + 0xCE, 0x08, 0x69, 0x8B, 0x87, 0x62, 0x36, 0xB1, 0x7B, 0xDE, 0x74, 0xBD, 0xFE, + 0x10, 0xBE, 0x26, 0xAB, 0x7E, 0xB7, 0x8D, 0xF7, 0x83, 0x2E, 0x0F, 0xAF, 0x7E, + 0xBC, 0x17, 0x31, 0xFF, 0xB0, 0x4F, 0x7F, 0x4B, 0x13, 0x83, 0xDF, 0xEE, 0x23, + 0xD3, 0xE7, 0xC8, 0xAF, 0x75, 0xAB, 0xEA, 0xBD, 0x7D, 0xD2, 0x9D, 0xE9, 0xC1, + 0x18, 0x8B, 0x7C, 0x9F, 0x51, 0xDC, 0x37, 0xA3, 0xDB, 0xFC, 0xD4, 0x6A, 0x91, + 0x44, 0x7F, 0x72, 0xC5, 0xD9, 0xC8, 0x37, 0x38, 0x63, 0x0D, 0x59, 0x8B, 0x7F, + 0x7D, 0x96, 0xC1, 0x5F, 0x4C, 0x7C, 0x88, 0xCB, 0x65, 0x07, 0x2B, 0x0E, 0x1D, + 0x24, 0xAA, 0x20, 0x2E, 0x6C, 0x33, 0xAB, 0xEF, 0x23, 0xE5, 0xE3, 0x6C, 0xA3, + 0xA5, 0x2D, 0x01, 0xDF, 0x26, 0x92, 0x52, 0xF5, 0xE6, 0x3E, 0xE3, 0xDD, 0xC6, + 0xED, 0x42, 0x0F, 0x71, 0x7B, 0xD1, 0xF4, 0x06, 0xF6, 0x82, 0xD5, 0x13, 0xB3, + 0x60, 0x31, 0x09, 0x89, 0x63, 0x15, 0xD2, 0xCB, 0xAA, 0x77, 0xFD, 0xF4, 0xEB, + 0xF4, 0xED, 0x2E, 0xE2, 0xBA, 0x27, 0x2E, 0x74, 0xD2, 0x91, 0x7F, 0x0F, 0xDE, + 0x25, 0xFE, 0x78, 0x20, 0x05, 0x0A, 0x6A, 0xFE, 0x89, 0x14, 0x23, 0xF3, 0xF5, + 0x3A, 0x1E, 0xF3, 0x22, 0xCE, 0x12, 0x82, 0x24, 0x11, 0x05, 0x04, 0x71, 0x99, + 0xE5, 0xF0, 0xA6, 0xDB, 0x7B, 0xF5, 0x8F, 0xF9, 0x3C, 0x02, 0x0C, 0x46, 0xFD, + 0xB6, 0xEA, 0x06, 0x11, 0xF4, 0x1E, 0x7A, 0x20, 0x6A, 0x54, 0xBB, 0x4A, 0x60, + 0xB0, 0x30, 0x28, 0x9A, 0xF3, 0x3B, 0xE9, 0xBD, 0xD6, 0x04, 0xCA, 0x3A, 0x33, + 0x37, 0x5F, 0xB7, 0xAD, 0xE7, 0x9C, 0xE2, 0x95, 0x21, 0xF7, 0xB5, 0xC4, 0xF0, + 0xD1, 0x51, 0x09, 0x44, 0x3F, 0x07, 0xFC, 0x5F, 0x37, 0xFD, 0x7D, 0x7E, 0xD5, + 0xF7, 0xEB, 0x69, 0xB9, 0x54, 0x98, 0x5A, 0x2A, 0x56, 0xE3, 0xC0, 0x21, 0x57, + 0xD1, 0xEB, 0x75, 0x15, 0xED, 0xAC, 0xAF, 0x5D, 0xFF, 0xC2, 0xFE, 0x4E, 0xFB, + 0xBA, 0x13, 0xB8, 0x87, 0xFA, 0x4E, 0x5E, 0x5C, 0x24, 0x15, 0x5B, 0x2B, 0x2C, + 0x32, 0x68, 0x1F, 0x30, 0x5F, 0xC1, 0xF7, 0xE7, 0xE1, 0x9C, 0x00, 0xC1, 0x9C, + 0xB1, 0xAB, 0xFA, 0xFF, 0xC1, 0x1E, 0x72, 0xA1, 0x46, 0x9E, 0x2E, 0xCD, 0x76, + 0x96, 0x4F, 0x14, 0xDC, 0x68, 0xC1, 0x10, 0x9F, 0xDF, 0xEB, 0x5A, 0xBA, 0x8D, + 0x91, 0x4E, 0x76, 0xE9, 0x3A, 0x43, 0x2D, 0x88, 0xD2, 0x81, 0x0C, 0xEC, 0x6F, + 0xB7, 0xA4, 0x8B, 0x97, 0x4F, 0xC4, 0x1E, 0xF3, 0x0F, 0xF5, 0x66, 0x66, 0xBF, + 0x6C, 0x3F, 0xFB, 0x6E, 0x2B, 0x48, 0x6C, 0x7B, 0xD1, 0x2E, 0x64, 0xD1, 0x0B, + 0x6E, 0x5B, 0x05, 0x16, 0xDD, 0xCB, 0x1B, 0xDE, 0xA2, 0xB9, 0xA8, 0x94, 0xD6, + 0x5A, 0x5B, 0xE2, 0xC9, 0xBC, 0xD5, 0xAB, 0x64, 0x5B, 0x0F, 0x9A, 0xFD, 0xC7, + 0x2E, 0xB7, 0xEF, 0xAE, 0xE9, 0x1F, 0x32, 0xD2, 0xCA, 0xA0, 0x37, 0x63, 0x86, + 0x72, 0x41, 0x07, 0xBC, 0xAB, 0x6F, 0xFF, 0xB7, 0x16, 0xAA, 0xA9, 0x58, 0x9E, + 0x43, 0x9C, 0x22, 0x8D, 0x48, 0xCE, 0xE5, 0xEF, 0xE0, 0x7D, 0x47, 0x87, 0x5A, + 0xA8, 0x5B, 0x06, 0xA9, 0x47, 0xF0, 0x26, 0xB4, 0x99, 0xD8, 0xA3, 0x64, 0xED, + 0x73, 0xB3, 0x96, 0xB4, 0x21, 0x19, 0xA5, 0xC1, 0xDC, 0x88, 0x2E, 0xEE, 0xF2, + 0x77, 0x91, 0xEC, 0xFB, 0xD5, 0xF9, 0xF8, 0x90, 0x47, 0xAD, 0xF5, 0xEB, 0x96, + 0x6D, 0xF1, 0x1C, 0xE0, 0xDC, 0x74, 0x1C, 0xE6, 0x2E, 0xE1, 0x76, 0x9D, 0xEE, + 0xF4, 0xEF, 0xA5, 0x31, 0x03, 0x87, 0x0E, 0x2C, 0x84, 0xA5, 0xF1, 0x22, 0xBE, + 0x48, 0xA9, 0xCD, 0x09, 0x07, 0xC1, 0xF0, 0xD4, 0xE7, 0x03, 0x82, 0x39, 0xE2, + 0xA0, 0x0B, 0xDE, 0xAC, 0x37, 0xAC, 0x62, 0x97, 0x8E, 0x79, 0xCE, 0x52, 0x24, + 0x78, 0xF9, 0x17, 0xD2, 0xF1, 0x5D, 0x2D, 0xA1, 0xDF, 0x12, 0x2C, 0x83, 0xE5, + 0x1A, 0x28, 0x9A, 0x2D, 0xED, 0x8A, 0xBF, 0xFC, 0x41, 0xC3, 0xEB, 0x0E, 0x91, + 0xDB, 0xF2, 0xA1, 0xC8, 0xA8, 0x01, 0x8B, 0xF2, 0xF3, 0x59, 0xB7, 0xA7, 0x6F, + 0x80, 0xFF, 0x0B, 0x46, 0xE1, 0x63, 0xA7, 0x5F, 0x6B, 0xBE, 0x33, 0x71, 0xBE, + 0x3A, 0xAF, 0xA9, 0x53, 0x5D, 0x3B, 0xB2, 0xF6, 0xEB, 0x42, 0x1C, 0x3E, 0x3F, + 0x1D, 0x6A, 0x34, 0xAE, 0xB1, 0x05, 0xA1, 0x32, 0x6C, 0xB5, 0xE4, 0xD3, 0xBB, + 0xE8, 0x10, 0x14, 0x9E, 0x68, 0x6A, 0x24, 0x51, 0xA5, 0x66, 0x64, 0xCC, 0xC4, + 0x2D, 0x96, 0xA2, 0xC7, 0x2D, 0x1F, 0x0A, 0x0F, 0x6B, 0xD9, 0xAD, 0xA3, 0x11, + 0x8F, 0x00, 0xAA, 0x06, 0xC2, 0x1E, 0xF3, 0xE8, 0x5A, 0x37, 0x4C, 0xD6, 0x4B, + 0x6B, 0x01, 0xC9, 0xB0, 0xB6, 0xB9, 0x92, 0xED, 0x1D, 0x08, 0xB0, 0x80, 0x06, + 0x20, 0xEA, 0xEE, 0xF9, 0x1D, 0xA4, 0x57, 0x73, 0x2E, 0x1B, 0xA5, 0xAF, 0xF6, + 0xAF, 0xAE, 0x04, 0x7C, 0x4C, 0x7E, 0xC8, 0xDB, 0xC0, 0xFB, 0x37, 0xC8, 0x7E, + 0xFE, 0x47, 0x0A, 0x3C, 0xFA, 0x61, 0xE7, 0xEB, 0x1B, 0xF3, 0x7C, 0x32, 0xE3, + 0x7C, 0x37, 0x66, 0x7C, 0x53, 0x07, 0xC2, 0x37, 0xA3, 0xBD, 0xF7, 0xFA, 0xE3, + 0x8A, 0x76, 0xCB, 0x6C, 0xC8, 0x13, 0xC4, 0x53, 0x53, 0xDB, 0xAD, 0x37, 0x1A, + 0xEB, 0xE0 +}; + +// Class for testing the FFmpegH264BitstreamConverter. +class FFmpegH264BitstreamConverterTest : public testing::Test { + protected: + FFmpegH264BitstreamConverterTest() { + // Set up the ffmpeg mock and use our local fake functions to do the + // actual implementation for packet allocation / freeing. + MockFFmpeg::set(&ffmpeg_mock_); + ON_CALL(ffmpeg_mock_, AVInitPacket(_)) + .WillByDefault(Invoke(fake_av_init_packet)); + ON_CALL(ffmpeg_mock_, AVNewPacket(_, _)) + .WillByDefault(Invoke(fake_av_new_packet)); + ON_CALL(ffmpeg_mock_, AVDestructPacket(_)) + .WillByDefault(Invoke(fake_av_destruct_packet)); + // Set up AVCConfigurationRecord correctly for tests. + // It's ok to do const cast here as data in kHeaderDataOkWithFieldLen4 is + // never written to. + memset(&test_context_, 0, sizeof(AVCodecContext)); + test_context_.extradata = const_cast<uint8*>(kHeaderDataOkWithFieldLen4); + test_context_.extradata_size = sizeof(kHeaderDataOkWithFieldLen4); + } + + virtual ~FFmpegH264BitstreamConverterTest() {} + + void CreatePacket(AVPacket* packet, const uint8* data, uint32 data_size) { + // Create new packet sized of |data_size| from |data|. + EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _)); + EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_)); + EXPECT_EQ(av_new_packet(packet, data_size), 0); + memcpy(packet->data, data, data_size); + } + + // FFmpeg mock implementation. We want strict mock since we will strictly + // define the order of calls and do not want any extra calls. + StrictMock<MockFFmpeg> ffmpeg_mock_; + + // Variable to hold valid dummy context for testing. + AVCodecContext test_context_; + + private: + DISALLOW_COPY_AND_ASSIGN(FFmpegH264BitstreamConverterTest); +}; + +TEST_F(FFmpegH264BitstreamConverterTest, Conversion_Success) { + FFmpegH264BitstreamConverter converter(&test_context_); + + // Initialization should be always successful. + EXPECT_TRUE(converter.Initialize()); + + AVPacket test_packet; + CreatePacket(&test_packet, kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + + // Try out the actual conversion (should be successful and allocate new + // packet and destroy the old one). + EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _)); + EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_)); + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + EXPECT_TRUE(converter.ConvertPacket(&test_packet)); + + // Clean-up the test packet. + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + av_destruct_packet(&test_packet); + + // Converter will be automatically cleaned up. +} + +TEST_F(FFmpegH264BitstreamConverterTest, Conversion_SuccessBigPacket) { + FFmpegH264BitstreamConverter converter(&test_context_); + + // Initialization should be always successful. + EXPECT_TRUE(converter.Initialize()); + + // Create new packet with 1000 excess bytes. + AVPacket test_packet; + static uint8 excess_data[sizeof(kPacketDataOkWithFieldLen4) + 1000] = {0}; + memcpy(excess_data, kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + CreatePacket(&test_packet, excess_data, sizeof(excess_data)); + + // Try out the actual conversion (should be successful and allocate new + // packet and destroy the old one as we do NOT support in place transform). + EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _)); + EXPECT_CALL(ffmpeg_mock_, AVInitPacket(_)); + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + EXPECT_TRUE(converter.ConvertPacket(&test_packet)); + + // Clean-up the test packet. + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + av_destruct_packet(&test_packet); + + // Converter will be automatically cleaned up. +} + +TEST_F(FFmpegH264BitstreamConverterTest, Conversion_FailureOutOfMem) { + FFmpegH264BitstreamConverter converter(&test_context_); + + // Initialization should be always successful. + EXPECT_TRUE(converter.Initialize()); + + // Create new packet. + AVPacket test_packet; + CreatePacket(&test_packet, kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + + // Try out the actual conversion (should be successful and allocate new + // packet and destroy the old one). + EXPECT_CALL(ffmpeg_mock_, AVNewPacket(_, _)) + .WillOnce(Return(-1)); + EXPECT_FALSE(converter.ConvertPacket(&test_packet)) + << "ConvertPacket() did not return expected failure due to out of mem"; + + // Clean-up the test packet. + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + av_destruct_packet(&test_packet); + + // Converter will be automatically cleaned up. +} + +TEST_F(FFmpegH264BitstreamConverterTest, Conversion_FailureNullParams) { + // Set up AVCConfigurationRecord to represent NULL data. + AVCodecContext dummy_context; + dummy_context.extradata = NULL; + dummy_context.extradata_size = 0; + FFmpegH264BitstreamConverter converter(&dummy_context); + + // Initialization should be always successful. + EXPECT_TRUE(converter.Initialize()); + + // Try out the actual conversion with NULL parameter. + EXPECT_FALSE(converter.ConvertPacket(NULL)); + + // Create new packet to test actual conversion. + AVPacket test_packet; + CreatePacket(&test_packet, kPacketDataOkWithFieldLen4, + sizeof(kPacketDataOkWithFieldLen4)); + + // Try out the actual conversion (should be successful and allocate new + // packet and destroy the old one). This should fail due to missing extradata. + EXPECT_FALSE(converter.ConvertPacket(&test_packet)); + + // Clean-up the test packet. + EXPECT_CALL(ffmpeg_mock_, AVDestructPacket(_)); + av_destruct_packet(&test_packet); + + // Converted will be automatically cleaned up. +} + +static void fake_av_destruct_packet(AVPacket* pkt) { + free(pkt->data); + pkt->data = NULL; + pkt->size = 0; +} + +static void fake_av_init_packet(AVPacket* pkt) { + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; + pkt->duration = 0; + pkt->convergence_duration = 0; + pkt->flags = 0; + pkt->stream_index = 0; + pkt->destruct= NULL; +} + +static int fake_av_new_packet(AVPacket* pkt, int size) { + uint8* data = reinterpret_cast<uint8*>(malloc(size)); + av_init_packet(pkt); + pkt->data = data; + pkt->size = size; + pkt->destruct = av_destruct_packet; + if (data == NULL) + return AVERROR(ENOMEM); + return 0; +} + +} // namespace media + diff --git a/media/media.gyp b/media/media.gyp index 7533cd1..f33d191 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -89,6 +89,8 @@ 'base/filter_host.h', 'base/filters.cc', 'base/filters.h', + 'base/h264_bitstream_converter.cc', + 'base/h264_bitstream_converter.h', 'base/media.h', 'base/media_format.cc', 'base/media_format.h', @@ -144,6 +146,8 @@ 'filters/ffmpeg_audio_decoder.h', 'filters/ffmpeg_demuxer.cc', 'filters/ffmpeg_demuxer.h', + 'filters/ffmpeg_h264_bitstream_converter.cc', + 'filters/ffmpeg_h264_bitstream_converter.h', 'filters/ffmpeg_glue.cc', 'filters/ffmpeg_glue.h', 'filters/ffmpeg_interfaces.cc', @@ -289,6 +293,7 @@ 'base/data_buffer_unittest.cc', 'base/djb2_unittest.cc', 'base/filter_collection_unittest.cc', + 'base/h264_bitstream_converter_unittest.cc', 'base/mock_ffmpeg.cc', 'base/mock_ffmpeg.h', 'base/mock_reader.h', @@ -307,6 +312,7 @@ 'filters/decoder_base_unittest.cc', 'filters/ffmpeg_demuxer_unittest.cc', 'filters/ffmpeg_glue_unittest.cc', + 'filters/ffmpeg_h264_bitstream_converter_unittest.cc', 'filters/ffmpeg_video_decoder_unittest.cc', 'filters/file_data_source_unittest.cc', 'filters/video_renderer_base_unittest.cc', @@ -457,7 +463,7 @@ ], 'sources': [ 'tools/mfplayer/mfplayer.h', - 'tools/mfplayer/mfplayer.cc', + 'tools/mfplayer/mfplayer.cc', 'tools/mfplayer/mf_playback_main.cc', ], 'msvs_settings': { @@ -478,7 +484,7 @@ ], 'sources': [ 'tools/mfdecoder/main.cc', - 'tools/mfdecoder/mfdecoder.h', + 'tools/mfdecoder/mfdecoder.h', 'tools/mfdecoder/mfdecoder.cc', ], 'msvs_settings': { diff --git a/media/tools/player_x11/gles_video_renderer.cc b/media/tools/player_x11/gles_video_renderer.cc index 104de5f..3ccc065 100644 --- a/media/tools/player_x11/gles_video_renderer.cc +++ b/media/tools/player_x11/gles_video_renderer.cc @@ -18,6 +18,12 @@ GlesVideoRenderer* GlesVideoRenderer::instance_ = NULL; +// TODO(vmr): Refactor this parameter to work either through environment +// variable or dynamically sniff whether EGL support is available. +static inline int uses_egl_image() { + return 1; +} + GlesVideoRenderer::GlesVideoRenderer(Display* display, Window window, MessageLoop* message_loop) : egl_create_image_khr_(NULL), @@ -129,6 +135,8 @@ static const char kFragmentShader[] = // Color shader for EGLImage. static const char kFragmentShaderEgl[] = + "precision mediump float;\n" + "precision mediump int;\n" "varying vec2 interp_tc;\n" "\n" "uniform sampler2D tex;\n" diff --git a/media/tools/player_x11/gles_video_renderer.h b/media/tools/player_x11/gles_video_renderer.h index 3fcb89a..25c7dbb 100644 --- a/media/tools/player_x11/gles_video_renderer.h +++ b/media/tools/player_x11/gles_video_renderer.h @@ -13,6 +13,7 @@ #include <utility> #include <vector> +#include "base/message_loop.h" #include "base/scoped_ptr.h" #include "media/base/filters.h" #include "media/base/video_frame.h" |