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