OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "media/formats/mp4/hevc.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "base/logging.h" | |
11 #include "media/base/decrypt_config.h" | |
12 #include "media/filters/h265_parser.h" | |
13 #include "media/formats/mp4/avc.h" | |
14 #include "media/formats/mp4/box_definitions.h" | |
15 #include "media/formats/mp4/box_reader.h" | |
16 | |
17 namespace media { | |
18 namespace mp4 { | |
19 | |
20 static const uint8 kAnnexBStartCode[] = {0, 0, 0, 1}; | |
21 static const int kAnnexBStartCodeSize = 4; | |
22 | |
23 bool HEVC::InsertParamSetsAnnexB( | |
24 const HEVCDecoderConfigurationRecord& hevc_config, | |
25 std::vector<uint8>* buffer, | |
26 std::vector<SubsampleEntry>* subsamples) { | |
27 DCHECK(HEVC::IsValidAnnexB(*buffer, *subsamples)); | |
28 | |
29 scoped_ptr<H265Parser> parser(new H265Parser()); | |
30 const uint8* start = &(*buffer)[0]; | |
31 parser->SetEncryptedStream(start, buffer->size(), *subsamples); | |
32 | |
33 H265NALU nalu; | |
34 if (parser->AdvanceToNextNALU(&nalu) != H265Parser::kOk) | |
35 return false; | |
36 | |
37 std::vector<uint8>::iterator config_insert_point = buffer->begin(); | |
38 | |
39 if (nalu.nal_unit_type == H265NALU::AUD_NUT) { | |
40 // Move insert point to just after the AUD. | |
41 config_insert_point += (nalu.data + nalu.size) - start; | |
42 } | |
43 | |
44 // Clear |parser| and |start| since they aren't needed anymore and | |
45 // will hold stale pointers once the insert happens. | |
46 parser.reset(); | |
47 start = NULL; | |
48 | |
49 std::vector<uint8> param_sets; | |
50 RCHECK(HEVC::ConvertConfigToAnnexB(hevc_config, ¶m_sets)); | |
51 DVLOG(4) << __FUNCTION__ << " converted hvcC to AnnexB " | |
52 << " size=" << param_sets.size() << " inserted at " | |
53 << (int)(config_insert_point - buffer->begin()); | |
54 | |
55 if (subsamples && !subsamples->empty()) { | |
56 int subsample_index = AVC::FindSubsampleIndex(*buffer, subsamples, | |
57 &(*config_insert_point)); | |
58 // Update the size of the subsample where SPS/PPS is to be inserted. | |
59 (*subsamples)[subsample_index].clear_bytes += param_sets.size(); | |
60 } | |
61 | |
62 buffer->insert(config_insert_point, | |
63 param_sets.begin(), param_sets.end()); | |
64 | |
65 DCHECK(HEVC::IsValidAnnexB(*buffer, *subsamples)); | |
66 return true; | |
67 } | |
68 | |
69 bool HEVC::ConvertConfigToAnnexB( | |
70 const HEVCDecoderConfigurationRecord& hevc_config, | |
71 std::vector<uint8>* buffer) { | |
72 DCHECK(buffer->empty()); | |
73 buffer->clear(); | |
74 | |
75 for (size_t j = 0; j < hevc_config.arrays.size(); j++) { | |
76 uint8 naluType = hevc_config.arrays[j].first_byte & 0x3f; | |
77 for (size_t i = 0; i < hevc_config.arrays[j].units.size(); ++i) { | |
78 DVLOG(3) << __FUNCTION__ << " naluType=" << (int)naluType | |
79 << " size=" << hevc_config.arrays[j].units[i].size(); | |
80 buffer->insert(buffer->end(), kAnnexBStartCode, | |
81 kAnnexBStartCode + kAnnexBStartCodeSize); | |
82 buffer->insert(buffer->end(), hevc_config.arrays[j].units[i].begin(), | |
83 hevc_config.arrays[j].units[i].end()); | |
84 } | |
85 } | |
86 | |
87 return true; | |
88 } | |
89 | |
90 // Verifies AnnexB NALU order according to section 7.4.2.4.4 of ISO/IEC 23008-2. | |
91 bool HEVC::IsValidAnnexB(const std::vector<uint8>& buffer, | |
92 const std::vector<SubsampleEntry>& subsamples) { | |
93 return IsValidAnnexB(&buffer[0], buffer.size(), subsamples); | |
94 } | |
95 | |
96 bool HEVC::IsValidAnnexB(const uint8* buffer, size_t size, | |
97 const std::vector<SubsampleEntry>& subsamples) { | |
98 DCHECK(buffer); | |
99 | |
100 if (size == 0) | |
101 return true; | |
102 | |
103 // TODO(servolk): Implement this | |
wolenetz
2015/09/02 20:43:18
nit: reference a bug?
servolk
2015/09/03 00:17:51
Done, crbug.com/527595
| |
104 return true; | |
105 } | |
106 | |
107 HEVCBitstreamConverter::HEVCBitstreamConverter( | |
108 scoped_ptr<HEVCDecoderConfigurationRecord> hevc_config) | |
109 : hevc_config_(hevc_config.Pass()) { | |
110 DCHECK(hevc_config_); | |
111 } | |
112 | |
113 HEVCBitstreamConverter::~HEVCBitstreamConverter() { | |
114 } | |
115 | |
116 bool HEVCBitstreamConverter::ConvertFrame( | |
117 std::vector<uint8>* frame_buf, | |
118 bool is_keyframe, | |
119 std::vector<SubsampleEntry>* subsamples) const { | |
120 RCHECK(AVC::ConvertFrameToAnnexB(hevc_config_->lengthSizeMinusOne + 1, | |
121 frame_buf, subsamples)); | |
122 | |
123 if (is_keyframe) { | |
124 // If this is a keyframe, we (re-)inject HEVC params headers at the start of | |
125 // a frame. If subsample info is present, we also update the clear byte | |
126 // count for that first subsample. | |
127 RCHECK(HEVC::InsertParamSetsAnnexB(*hevc_config_, frame_buf, subsamples)); | |
128 } | |
129 | |
130 DCHECK(HEVC::IsValidAnnexB(*frame_buf, *subsamples)); | |
131 return true; | |
132 } | |
133 | |
134 } // namespace mp4 | |
135 } // namespace media | |
OLD | NEW |