| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012 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 |
| 5 #include "content/common/gpu/media/avc_config_record_builder.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "content/common/gpu/media/h264_parser.h" |
| 9 |
| 10 namespace content { |
| 11 |
| 12 AVCConfigRecordBuilder::AVCConfigRecordBuilder() |
| 13 : sps_profile_idc_(0), |
| 14 sps_constraint_setx_flag_(0), |
| 15 sps_level_idc_(0), |
| 16 coded_width_(0), |
| 17 coded_height_(0) { |
| 18 } |
| 19 |
| 20 AVCConfigRecordBuilder::~AVCConfigRecordBuilder() { |
| 21 } |
| 22 |
| 23 bool AVCConfigRecordBuilder::ProcessNALU( |
| 24 H264Parser* parser, |
| 25 const H264NALU& nalu, |
| 26 std::vector<uint8>* config_record) { |
| 27 if (nalu.nal_unit_type == H264NALU::kSPS) { |
| 28 return ProcessSPS(parser, nalu); |
| 29 } else if (nalu.nal_unit_type == H264NALU::kPPS) { |
| 30 return ProcessPPS(parser, nalu); |
| 31 } else if (nalu.nal_unit_type >= 1 && nalu.nal_unit_type <= 5) { |
| 32 // Ready to build the AVC decoder configuration record once the first slice |
| 33 // type is encountered. |
| 34 *config_record = BuildConfigRecord(); |
| 35 return true; |
| 36 } |
| 37 // Effectively skip this NALU by returning success. |
| 38 return true; |
| 39 } |
| 40 |
| 41 std::vector<uint8> AVCConfigRecordBuilder::BuildConfigRecord() { |
| 42 // 5 bytes for AVC record header. 1 byte for the number of SPS units. |
| 43 // 1 byte for the number of PPS units. |
| 44 int record_size = 7; |
| 45 for (NALUVector::const_iterator it = sps_nalus_.begin(); |
| 46 it != sps_nalus_.end(); ++it) { |
| 47 // Plus 2 bytes to store the SPS size. |
| 48 record_size += (*it)->size() + 2; |
| 49 } |
| 50 for (NALUVector::const_iterator it = pps_nalus_.begin(); |
| 51 it != pps_nalus_.end(); ++it) { |
| 52 // Plus 2 bytes to store the PPS size. |
| 53 record_size += (*it)->size() + 2; |
| 54 } |
| 55 std::vector<uint8> extra_data(record_size); |
| 56 |
| 57 // AVC decoder configuration record version. |
| 58 extra_data[0] = 0x01; |
| 59 // Profile. |
| 60 extra_data[1] = sps_profile_idc_ & 0xff; |
| 61 // Profile compatibility, must match the byte between profile IDC |
| 62 // and level IDC in the SPS. |
| 63 extra_data[2] = sps_constraint_setx_flag_; |
| 64 // AVC level. |
| 65 extra_data[3] = sps_level_idc_ & 0xff; |
| 66 |
| 67 // TODO(sail): There's no way to get the NALU length field size from the |
| 68 // SPS and PPS data. Just assume 4 for now. |
| 69 const int kNALULengthFieldSize = 4; |
| 70 |
| 71 // The first 6 bits are reserved and must be 1. Last two bits are the |
| 72 // NALU field size minus 1. |
| 73 extra_data[4] = 0xfc | ((kNALULengthFieldSize - 1) & 0x03); |
| 74 |
| 75 // The first 3 bits are reserved and must be 1. Last 5 bits are the |
| 76 // number of SPS units. |
| 77 extra_data[5] = 0xe0 | (sps_nalus_.size() & 0x1f); |
| 78 int index = 6; |
| 79 if (!sps_nalus_.empty()) |
| 80 index += CopyNALUsToConfigRecord(sps_nalus_, &extra_data[index]); |
| 81 |
| 82 // The number of PPS units. |
| 83 extra_data[index++] = pps_nalus_.size() & 0xff; |
| 84 if (!pps_nalus_.empty()) |
| 85 CopyNALUsToConfigRecord(pps_nalus_, &extra_data[index]); |
| 86 |
| 87 return extra_data; |
| 88 } |
| 89 |
| 90 int AVCConfigRecordBuilder::CopyNALUsToConfigRecord(const NALUVector& nalus, |
| 91 uint8* record_buffer) { |
| 92 int index = 0; |
| 93 for (NALUVector::const_iterator it = nalus.begin(); |
| 94 it != nalus.end(); ++it) { |
| 95 // High byte of the NALU size. |
| 96 record_buffer[index++] = ((*it)->size() >> 8) & 0xff; |
| 97 // Low byte of the NALU size. |
| 98 record_buffer[index++] = (*it)->size() & 0xff; |
| 99 // The NALU data. |
| 100 memcpy(record_buffer + index, (*it)->front(), (*it)->size()); |
| 101 index += (*it)->size(); |
| 102 } |
| 103 return index; |
| 104 } |
| 105 |
| 106 bool AVCConfigRecordBuilder::ProcessSPS(H264Parser* parser, |
| 107 const H264NALU& nalu) { |
| 108 int sps_id = 0; |
| 109 H264Parser::Result result = parser->ParseSPS(&sps_id); |
| 110 if (result != H264Parser::kOk) |
| 111 return false; |
| 112 |
| 113 std::vector<uint8> bytes(nalu.data, nalu.data + nalu.size); |
| 114 sps_nalus_.push_back(base::RefCountedBytes::TakeVector(&bytes)); |
| 115 |
| 116 const H264SPS* sps = parser->GetSPS(sps_id); |
| 117 |
| 118 // Use the last width and height that are encountered. |
| 119 coded_width_ = (sps->pic_width_in_mbs_minus1 + 1) * 16; |
| 120 if (sps->frame_mbs_only_flag) |
| 121 coded_height_ = (sps->pic_height_in_map_units_minus1 + 1) * 16; |
| 122 else |
| 123 coded_height_ = (sps->pic_height_in_map_units_minus1 + 1) * 32; |
| 124 |
| 125 // Use the last video profile and flags that are encountered. |
| 126 sps_profile_idc_ = sps->profile_idc; |
| 127 sps_constraint_setx_flag_ = sps->constraint_setx_flag; |
| 128 // Use the largest AVC level that's encountered. |
| 129 sps_level_idc_ = std::max(sps_level_idc_, sps->level_idc); |
| 130 |
| 131 return true; |
| 132 } |
| 133 |
| 134 bool AVCConfigRecordBuilder::ProcessPPS(H264Parser* parser, |
| 135 const H264NALU& nalu) { |
| 136 int pps_id = 0; |
| 137 H264Parser::Result result = parser->ParsePPS(&pps_id); |
| 138 if (result != H264Parser::kOk) |
| 139 return false; |
| 140 |
| 141 std::vector<uint8> bytes(nalu.data, nalu.data + nalu.size); |
| 142 pps_nalus_.push_back(base::RefCountedBytes::TakeVector(&bytes)); |
| 143 return true; |
| 144 } |
| 145 |
| 146 } // namespace content |
| OLD | NEW |