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;
}
}