h264_annex_b_to_avc_bitstream_converter.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/formats/mp4/h264_annex_b_to_avc_bitstream_converter.h"
  5. #include "base/big_endian.h"
  6. #include "base/containers/flat_set.h"
  7. namespace media {
  8. H264AnnexBToAvcBitstreamConverter::H264AnnexBToAvcBitstreamConverter() {
  9. // These parts of configuration never change.
  10. config_.version = 1;
  11. config_.length_size = 4;
  12. }
  13. H264AnnexBToAvcBitstreamConverter::~H264AnnexBToAvcBitstreamConverter() =
  14. default;
  15. const mp4::AVCDecoderConfigurationRecord&
  16. H264AnnexBToAvcBitstreamConverter::GetCurrentConfig() {
  17. return config_;
  18. }
  19. MP4Status H264AnnexBToAvcBitstreamConverter::ConvertChunk(
  20. const base::span<const uint8_t> input,
  21. base::span<uint8_t> output,
  22. bool* config_changed_out,
  23. size_t* size_out) {
  24. std::vector<H264NALU> slice_units;
  25. size_t data_size = 0;
  26. bool config_changed = false;
  27. H264NALU nalu;
  28. H264Parser::Result result;
  29. int new_active_sps_id = -1;
  30. int new_active_pps_id = -1;
  31. // Sets of SPS and PPS ids to be included into the decoder config.
  32. // They contain
  33. // - all SPS and PPS units encountered in the input chunk;
  34. // - any SPS referenced by PPS units encountered in the input;
  35. // - The active SPS/PPS pair.
  36. base::flat_set<int> sps_to_include;
  37. base::flat_set<int> pps_to_include;
  38. // Scan input buffer looking for two main types of NALUs
  39. // 1. SPS and PPS. They'll be added to the AVC configuration |config_|
  40. // and will *not* be copied to |output|.
  41. // 2. Slices. They'll being copied into the output buffer, but also affect
  42. // what configuration (profile and level) is active now.
  43. parser_.SetStream(input.data(), input.size());
  44. while ((result = parser_.AdvanceToNextNALU(&nalu)) != H264Parser::kEOStream) {
  45. if (result == H264Parser::kUnsupportedStream)
  46. return MP4Status::Codes::kUnsupportedStream;
  47. if (result != H264Parser::kOk)
  48. return MP4Status::Codes::kFailedToParse;
  49. switch (nalu.nal_unit_type) {
  50. case H264NALU::kAUD: {
  51. break;
  52. }
  53. case H264NALU::kSPS: {
  54. int sps_id = -1;
  55. result = parser_.ParseSPS(&sps_id);
  56. if (result == H264Parser::kUnsupportedStream)
  57. return MP4Status::Codes::kInvalidSPS;
  58. if (result != H264Parser::kOk)
  59. return MP4Status::Codes::kInvalidSPS;
  60. id2sps_.insert_or_assign(sps_id,
  61. blob(nalu.data, nalu.data + nalu.size));
  62. sps_to_include.insert(sps_id);
  63. config_changed = true;
  64. break;
  65. }
  66. case H264NALU::kSPSExt: {
  67. // SPS extensions are not supported yet.
  68. break;
  69. }
  70. case H264NALU::kPPS: {
  71. int pps_id = -1;
  72. result = parser_.ParsePPS(&pps_id);
  73. if (result == H264Parser::kUnsupportedStream)
  74. return MP4Status::Codes::kInvalidPPS;
  75. if (result != H264Parser::kOk)
  76. return MP4Status::Codes::kInvalidPPS;
  77. id2pps_.insert_or_assign(pps_id,
  78. blob(nalu.data, nalu.data + nalu.size));
  79. pps_to_include.insert(pps_id);
  80. if (auto* pps = parser_.GetPPS(pps_id))
  81. sps_to_include.insert(pps->seq_parameter_set_id);
  82. config_changed = true;
  83. break;
  84. }
  85. case H264NALU::kSliceDataA:
  86. case H264NALU::kSliceDataB:
  87. case H264NALU::kSliceDataC:
  88. case H264NALU::kNonIDRSlice:
  89. case H264NALU::kIDRSlice: {
  90. H264SliceHeader slice_hdr;
  91. result = parser_.ParseSliceHeader(nalu, &slice_hdr);
  92. if (result != H264Parser::kOk) {
  93. return MP4Status::Codes::kInvalidSliceHeader;
  94. }
  95. const H264PPS* pps = parser_.GetPPS(slice_hdr.pic_parameter_set_id);
  96. if (!pps) {
  97. return MP4Status::Codes::kFailedToLookupPPS;
  98. }
  99. const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
  100. if (!sps) {
  101. return MP4Status::Codes::kFailedToLookupSPS;
  102. }
  103. new_active_pps_id = pps->pic_parameter_set_id;
  104. new_active_sps_id = sps->seq_parameter_set_id;
  105. pps_to_include.insert(new_active_pps_id);
  106. sps_to_include.insert(new_active_sps_id);
  107. if (new_active_sps_id != active_sps_id_) {
  108. if (!config_changed) {
  109. DCHECK(nalu.nal_unit_type == H264NALU::kIDRSlice)
  110. << "SPS shouldn't change in non-IDR slice";
  111. }
  112. config_changed = true;
  113. }
  114. }
  115. [[fallthrough]];
  116. default:
  117. slice_units.push_back(nalu);
  118. data_size += config_.length_size + nalu.size;
  119. break;
  120. }
  121. }
  122. if (size_out)
  123. *size_out = data_size;
  124. if (data_size > output.size()) {
  125. return MP4Status::Codes::kBufferTooSmall;
  126. }
  127. // Write slice NALUs from the input buffer to the output buffer
  128. // prefixing them with size.
  129. base::BigEndianWriter writer(reinterpret_cast<char*>(output.data()),
  130. output.size());
  131. for (auto& unit : slice_units) {
  132. bool written_ok =
  133. writer.WriteU32(unit.size) && writer.WriteBytes(unit.data, unit.size);
  134. if (!written_ok) {
  135. return MP4Status::Codes::kBufferTooSmall;
  136. }
  137. }
  138. DCHECK_LE(writer.remaining(), output.size());
  139. size_t bytes_written = output.size() - writer.remaining();
  140. DCHECK_EQ(bytes_written, data_size);
  141. // Now when we are sure that everything is written and fits nicely,
  142. // we can update parts of the |config_| that were changed by this data chunk.
  143. if (config_changed) {
  144. if (new_active_sps_id < 0)
  145. new_active_sps_id = active_sps_id_;
  146. if (new_active_pps_id < 0)
  147. new_active_pps_id = active_pps_id_;
  148. const H264SPS* active_sps = parser_.GetSPS(new_active_sps_id);
  149. if (!active_sps) {
  150. return MP4Status::Codes::kFailedToLookupSPS;
  151. }
  152. active_pps_id_ = new_active_pps_id;
  153. active_sps_id_ = new_active_sps_id;
  154. config_.sps_list.clear();
  155. config_.pps_list.clear();
  156. // flat_set is iterated in key-order
  157. for (int id : sps_to_include)
  158. config_.sps_list.push_back(id2sps_[id]);
  159. for (int id : pps_to_include)
  160. config_.pps_list.push_back(id2pps_[id]);
  161. config_.profile_indication = active_sps->profile_idc;
  162. config_.profile_compatibility =
  163. (active_sps->constraint_set0_flag ? 1 : 0) |
  164. (active_sps->constraint_set1_flag ? (1 << 1) : 0) |
  165. (active_sps->constraint_set2_flag ? (1 << 2) : 0) |
  166. (active_sps->constraint_set3_flag ? (1 << 3) : 0);
  167. config_.avc_level = active_sps->level_idc;
  168. }
  169. if (config_changed_out)
  170. *config_changed_out = config_changed;
  171. return OkStatus();
  172. }
  173. } // namespace media