#include "media/filters/h264_to_annex_b_bitstream_converter.h"
#include "base/logging.h"
+#include "media/filters/h264_parser.h"
+#include "media/formats/mp4/box_definitions.h"
namespace media {
static const uint8 kStartCodePrefix[3] = {0, 0, 1};
+static const uint32 kParamSetStartCodeSize = 1 + sizeof(kStartCodePrefix);
// Helper function which determines whether NAL unit of given type marks
// access unit boundary.
H264ToAnnexBBitstreamConverter::~H264ToAnnexBBitstreamConverter() {}
-uint32 H264ToAnnexBBitstreamConverter::ParseConfigurationAndCalculateSize(
+bool H264ToAnnexBBitstreamConverter::ParseConfiguration(
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;
- }
+ int configuration_record_size,
+ mp4::AVCDecoderConfigurationRecord* avc_config) {
+ DCHECK(configuration_record);
+ DCHECK_GT(configuration_record_size, 0);
+ DCHECK(avc_config);
+
+ if (!avc_config->Parse(configuration_record, configuration_record_size))
+ return false; // Error: invalid input
+
// We're done processing the AVCDecoderConfigurationRecord,
// store the needed information for parsing actual payload
- nal_unit_length_field_width_ = size_of_len_field;
+ nal_unit_length_field_width_ = avc_config->length_size;
configuration_processed_ = true;
- return parameter_set_size_bytes;
+ return true;
+}
+
+uint32 H264ToAnnexBBitstreamConverter::GetConfigSize(
+ const mp4::AVCDecoderConfigurationRecord& avc_config) const {
+ uint32 config_size = 0;
+
+ for (size_t i = 0; i < avc_config.sps_list.size(); ++i)
+ config_size += kParamSetStartCodeSize + avc_config.sps_list[i].size();
+
+ for (size_t i = 0; i < avc_config.pps_list.size(); ++i)
+ config_size += kParamSetStartCodeSize + avc_config.pps_list[i].size();
+
+ return config_size;
}
uint32 H264ToAnnexBBitstreamConverter::CalculateNeededOutputBufferSize(
const uint8* input,
- uint32 input_size) const {
+ uint32 input_size,
+ const mp4::AVCDecoderConfigurationRecord* avc_config) 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) {
+ if (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
}
+
+ if (avc_config)
+ output_size += GetConfigSize(*avc_config);
+
CHECK(nal_unit_length_field_width_ == 1 ||
nal_unit_length_field_width_ == 2 ||
nal_unit_length_field_width_ == 4);
}
bool H264ToAnnexBBitstreamConverter::ConvertAVCDecoderConfigToByteStream(
- const uint8* input,
- uint32 input_size,
+ const mp4::AVCDecoderConfigurationRecord& avc_config,
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
+ uint8* out = output;
+ uint32 out_size = *output_size;
+ *output_size = 0;
+ for (size_t i = 0; i < avc_config.sps_list.size(); ++i) {
+ if (!WriteParamSet(avc_config.sps_list[i], &out, &out_size))
+ return false;
}
- // 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;
+ for (size_t i = 0; i < avc_config.pps_list.size(); ++i) {
+ if (!WriteParamSet(avc_config.pps_list[i], &out, &out_size))
+ return false;
}
- // 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;
+
+ nal_unit_length_field_width_ = avc_config.length_size;
configuration_processed_ = true;
- *output_size = out_size;
+ *output_size = out - output;
return true;
}
bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
const uint8* input, uint32 input_size,
+ const mp4::AVCDecoderConfigurationRecord* avc_config,
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) {
+ if (input_size == 0 || *output_size == 0) {
*output_size = 0;
return false; // Error: invalid input
}
nal_unit_length_field_width_ == 4);
// Do the actual conversion for the actual input packet
+ int nal_unit_count = 0;
while (data_left > 0) {
uint8 i;
uint32 nal_unit_length;
return false; // Error: not enough data for correct conversion
}
+ // Five least significant bits of first NAL unit byte signify
+ // nal_unit_type.
+ int nal_unit_type = *inscan & 0x1F;
+ nal_unit_count++;
+
+ // Insert the config after the AUD if an AUD is the first NAL unit or
+ // before all NAL units if the first one isn't an AUD.
+ if (avc_config &&
+ (nal_unit_type != H264NALU::kAUD || nal_unit_count > 1)) {
+ uint32 output_bytes_used = outscan - output;
+
+ DCHECK_GE(*output_size, output_bytes_used);
+
+ uint32 config_size = *output_size - output_bytes_used;
+ if (!ConvertAVCDecoderConfigToByteStream(*avc_config,
+ outscan,
+ &config_size)) {
+ DVLOG(1) << "Failed to insert parameter sets.";
+ *output_size = 0;
+ return false; // Failed to convert the buffer.
+ }
+ outscan += config_size;
+ avc_config = NULL;
+ }
uint32 start_code_len;
first_nal_unit_in_access_unit_ ?
start_code_len = sizeof(kStartCodePrefix) + 1 :
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)) {
return true;
}
+bool H264ToAnnexBBitstreamConverter::WriteParamSet(
+ const std::vector<uint8>& param_set,
+ uint8** out,
+ uint32* out_size) const {
+ uint32 bytes_left = *out_size;
+ if (bytes_left < kParamSetStartCodeSize ||
+ bytes_left - kParamSetStartCodeSize < param_set.size()) {
+ return false;
+ }
+
+ uint8* start = *out;
+ uint8* buf = start;
+
+ // Write the 4 byte Annex B start code.
+ *buf++ = 0; // zero byte
+ memcpy(buf, kStartCodePrefix, sizeof(kStartCodePrefix));
+ buf += sizeof(kStartCodePrefix);
+
+ memcpy(buf, ¶m_set[0], param_set.size());
+ buf += param_set.size();
+
+ *out = buf;
+ *out_size -= buf - start;
+ return true;
+}
+
} // namespace media