This source file includes following definitions.
- IsAccessUnitBoundaryNal
- nal_unit_length_field_width_
- ParseConfigurationAndCalculateSize
- CalculateNeededOutputBufferSize
- ConvertAVCDecoderConfigToByteStream
- ConvertNalUnitStreamToByteStream
#include "media/filters/h264_to_annex_b_bitstream_converter.h"
#include "base/logging.h"
namespace media {
static const uint8 kStartCodePrefix[3] = {0, 0, 1};
static bool IsAccessUnitBoundaryNal(int nal_unit_type) {
if (nal_unit_type == 6 ||
nal_unit_type == 7 ||
nal_unit_type == 8 ||
nal_unit_type == 9 ||
(nal_unit_type >= 14 && nal_unit_type <= 18)) {
return true;
}
return false;
}
H264ToAnnexBBitstreamConverter::H264ToAnnexBBitstreamConverter()
: configuration_processed_(false),
first_nal_unit_in_access_unit_(true),
nal_unit_length_field_width_(0) {
}
H264ToAnnexBBitstreamConverter::~H264ToAnnexBBitstreamConverter() {}
uint32 H264ToAnnexBBitstreamConverter::ParseConfigurationAndCalculateSize(
const uint8* configuration_record,
uint32 configuration_record_size) {
if (configuration_record == NULL || configuration_record_size < 7) {
return 0;
}
const uint8* decoder_configuration = configuration_record;
uint32 parameter_set_size_bytes = 0;
decoder_configuration += 4;
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;
}
decoder_configuration++;
uint8 sps_count = *decoder_configuration & 0x1F;
decoder_configuration++;
while (sps_count-- > 0) {
if ((decoder_configuration - configuration_record) + 2 >
static_cast<int32>(configuration_record_size)) {
return 0;
}
uint16 sps_len = decoder_configuration[0] << 8 | decoder_configuration[1];
decoder_configuration += 2;
parameter_set_size_bytes += 1 + sizeof(kStartCodePrefix);
decoder_configuration += sps_len;
parameter_set_size_bytes += sps_len;
}
uint8 pps_count = *decoder_configuration;
decoder_configuration++;
while (pps_count-- > 0) {
if ((decoder_configuration - configuration_record) + 2 >
static_cast<int32>(configuration_record_size)) {
return 0;
}
uint16 pps_len = decoder_configuration[0] << 8 | decoder_configuration[1];
decoder_configuration += 2;
parameter_set_size_bytes += 1 + sizeof(kStartCodePrefix);
decoder_configuration += pps_len;
parameter_set_size_bytes += pps_len;
}
nal_unit_length_field_width_ = size_of_len_field;
configuration_processed_ = true;
return parameter_set_size_bytes;
}
uint32 H264ToAnnexBBitstreamConverter::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;
}
if (!configuration_processed_) {
return 0;
}
CHECK(nal_unit_length_field_width_ == 1 ||
nal_unit_length_field_width_ == 2 ||
nal_unit_length_field_width_ == 4);
while (data_left > 0) {
if (data_left < nal_unit_length_field_width_) {
return 0;
}
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;
} else if (nal_unit_length > data_left) {
return 0;
}
data_left -= nal_unit_length;
int nal_unit_type = *input & 0x1F;
if (first_nal_in_this_access_unit ||
IsAccessUnitBoundaryNal(nal_unit_type)) {
output_size += 1;
first_nal_in_this_access_unit = false;
}
output_size += sizeof(kStartCodePrefix);
output_size += nal_unit_length;
input += nal_unit_length;
}
return output_size;
}
bool H264ToAnnexBBitstreamConverter::ConvertAVCDecoderConfigToByteStream(
const uint8* input,
uint32 input_size,
uint8* output,
uint32* output_size) {
uint8* outscan = output;
const uint8* decoder_configuration = input;
uint32 decoderconfiguration_size = input_size;
uint32 out_size = 0;
if (decoder_configuration == NULL || decoderconfiguration_size == 0) {
return 0;
}
decoder_configuration += 4;
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;
}
decoder_configuration++;
uint8 sps_count = *decoder_configuration & 0x1F;
decoder_configuration++;
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;
}
*outscan = 0;
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;
}
uint8 pps_count = *decoder_configuration;
decoder_configuration++;
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;
}
*outscan = 0;
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;
}
nal_unit_length_field_width_ = size_of_len_field;
configuration_processed_ = true;
*output_size = out_size;
return true;
}
bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
const uint8* input, uint32 input_size,
uint8* output, uint32* output_size) {
const uint8* inscan = input;
uint8* outscan = output;
uint32 data_left = input_size;
if (inscan == NULL || input_size == 0 ||
outscan == NULL || *output_size == 0) {
*output_size = 0;
return false;
}
CHECK(nal_unit_length_field_width_ == 1 ||
nal_unit_length_field_width_ == 2 ||
nal_unit_length_field_width_ == 4);
while (data_left > 0) {
uint8 i;
uint32 nal_unit_length;
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;
} else if (nal_unit_length > data_left) {
*output_size = 0;
return false;
}
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;
}
int nal_unit_type = *inscan & 0x1F;
if (IsAccessUnitBoundaryNal(nal_unit_type)) {
first_nal_unit_in_access_unit_ = true;
}
if (first_nal_unit_in_access_unit_) {
*outscan = 0;
outscan++;
first_nal_unit_in_access_unit_ = false;
}
memcpy(outscan, kStartCodePrefix, sizeof(kStartCodePrefix));
outscan += sizeof(kStartCodePrefix);
memcpy(outscan, inscan, nal_unit_length);
inscan += nal_unit_length;
data_left -= nal_unit_length;
outscan += nal_unit_length;
}
*output_size = static_cast<uint32>(outscan - output);
return true;
}
}