Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / filters / h264_to_annex_b_bitstream_converter.cc
index fc45607..49456dd 100644 (file)
@@ -5,10 +5,13 @@
 #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.
@@ -33,80 +36,55 @@ H264ToAnnexBBitstreamConverter::H264ToAnnexBBitstreamConverter()
 
 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);
@@ -152,93 +130,37 @@ uint32 H264ToAnnexBBitstreamConverter::CalculateNeededOutputBufferSize(
 }
 
 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
   }
@@ -249,6 +171,7 @@ bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
         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;
@@ -269,6 +192,30 @@ bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
       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 :
@@ -279,10 +226,6 @@ bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
       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)) {
@@ -313,4 +256,30 @@ bool H264ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
   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, &param_set[0], param_set.size());
+  buf += param_set.size();
+
+  *out = buf;
+  *out_size -= buf - start;
+  return true;
+}
+
 }  // namespace media