Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: media/mpeg2/mpeg2ts_pes.cc

Issue 23566013: Mpeg2 TS stream parser for media source. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 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/mpeg2/mpeg2ts_pes.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "media/base/bit_reader.h"
10 #include "media/mpeg2/es_parser.h"
11 #include "media/mpeg2/mpeg2ts_common.h"
12 #include "media/mpeg2/mpeg2ts_def.h"
13
14 namespace {
15
16 int64 UnrollTimestamp(int64 previous_unrolled_time,
17 int64 time,
18 int nbits) {
19 // |timestamp| has a precision of |nbits|
20 // so make sure the highest bits are set to 0.
21 DCHECK_EQ((time >> nbits), 0);
22
23 // Consider 3 possibilities to estimate the missing high bits of |time|.
24 int64 previous_unrolled_time_high =
25 (previous_unrolled_time >> nbits);
26 int64 time0 = ((previous_unrolled_time_high - 1) << nbits) | time;
27 int64 time1 = ((previous_unrolled_time_high + 0) << nbits) | time;
28 int64 time2 = ((previous_unrolled_time_high + 1) << nbits) | time;
29
30 // Select the min absolute difference with the current time
31 // so as to ensure time continuity.
32 int64 diff0 = time0 - previous_unrolled_time;
33 int64 diff1 = time1 - previous_unrolled_time;
34 int64 diff2 = time2 - previous_unrolled_time;
35 if (diff0 < 0) {
36 diff0 = -diff0;
37 }
38 if (diff1 < 0) {
39 diff1 = -diff1;
40 }
41 if (diff2 < 0) {
42 diff2 = -diff2;
43 }
44
45 int64 unrolled_time;
46 int64 min_diff;
47 if (diff1 < diff0) {
48 unrolled_time = time1;
49 min_diff = diff1;
50 } else {
51 unrolled_time = time0;
52 min_diff = diff0;
53 }
54 if (diff2 < min_diff) {
55 unrolled_time = time2;
56 }
57 LOG_IF(INFO, unrolled_time != time1)
58 << "Unrolling time:"
59 << " previous_unrolled_time=" << previous_unrolled_time
60 << " time=" << time
61 << " unrolled_time=" << unrolled_time;
62
63 return unrolled_time;
64 }
65
66 bool IsTimestampSectionValid(int64 timestamp_section) {
67 // |pts_section| has 40 bits:
68 // - starting with either '0010' or '0011' or '0001'
69 // - and ending with a marker bit.
70 // See ITU H.222 standard - PES section.
71
72 // Verify that all the marker bits are one.
73 bool is_valid =
74 ((timestamp_section & 0x1) != 0) &&
75 ((timestamp_section & 0x10000) != 0) &&
76 ((timestamp_section & 0x100000000) != 0);
77 return is_valid;
78 }
79
80 int64 ConvertTimestampSectionToTimestamp(int64 timestamp_section) {
81 int64 timestamp =
82 (((timestamp_section >> 33) & 0x7) << 30) |
83 (((timestamp_section >> 17) & 0x7fff) << 15) |
84 (((timestamp_section >> 1) & 0x7fff) << 0);
85 return timestamp;
86 }
87
88 } // namespace
89
90 namespace media {
91 namespace mpeg2ts {
92
93 Mpeg2TsPesParser::Mpeg2TsPesParser(EsParser* es_parser)
94 : es_parser_(es_parser),
95 wait_for_unit_start_(true),
96 previous_pts_valid_(false),
97 previous_pts_(0),
98 previous_dts_valid_(false),
99 previous_dts_(0) {
100 }
101
102 Mpeg2TsPesParser::~Mpeg2TsPesParser() {
103 }
104
105 bool Mpeg2TsPesParser::Parse(bool payload_unit_start_indicator,
106 const uint8* buf, int size) {
107 if (wait_for_unit_start_ && !payload_unit_start_indicator) {
108 // Ignore partial PES.
109 return true;
110 }
111 wait_for_unit_start_ = false;
112
113 if (payload_unit_start_indicator) {
114 // If we have a pending packet with an undefined size
115 // (size == 0), try to parse and emit the previous packet.
116 if (raw_pes_.size() > 0) {
117 // TODO(damienv): should check the result of InternalParse for a possible
118 // error.
119 InternalParse();
120 raw_pes_.resize(0);
121 }
122 }
123
124 // Add the data to the parser state.
125 if (size > 0) {
126 int old_size = raw_pes_.size();
127 raw_pes_.resize(old_size + size);
128 memcpy(&raw_pes_[old_size], buf, size);
129 }
130
131 // Check whether we have enough data to start parsing.
132 if (raw_pes_.size() < 6)
133 return true;
134 int pes_packet_length =
135 (static_cast<int>(raw_pes_[4]) << 8) |
136 (static_cast<int>(raw_pes_[5]));
137 VLOG(LOG_LEVEL_PES) << "pes_packet_length=" << pes_packet_length;
138 if (pes_packet_length == 0) {
139 // Video packets are emitted when a new unit is coming
140 // since there is no way to know the size of the packet before.
141 return true;
142 }
143 if (static_cast<int>(raw_pes_.size()) < pes_packet_length + 6) {
144 // Don't throw an error when there is not enough data,
145 // just wait for more data to come.
146 return true;
147 }
148
149 // Parse the packet.
150 bool parse_result = InternalParse();
151 raw_pes_.resize(0);
152 return parse_result;
153 }
154
155 void Mpeg2TsPesParser::Flush() {
156 // Force emitting the previous buffer by faking a
157 // payload_unit_start_indicator.
158 // For video, the pes packet length is set to 0,
159 // thus a video packet can only be emitted when the next video
160 // packet is coming.
161 Parse(true, NULL, 0);
162 raw_pes_.resize(0);
163
164 // Flush the underlying ES parser.
165 es_parser_->Flush();
166 }
167
168 bool Mpeg2TsPesParser::InternalParse() {
169 BitReader bit_reader(&raw_pes_[0], raw_pes_.size());
170 int remaining_size = raw_pes_.size();
171
172 // Read:
173 // - packet_start_code_prefix
174 // - stream_id
175 // - pes_packet_length
176 if (remaining_size < 6) {
177 return false;
178 }
179 int packet_start_code_prefix;
180 DCHECK(bit_reader.ReadBits(24, &packet_start_code_prefix));
181 if (packet_start_code_prefix != 0x000001) {
182 LOG(WARNING) << "Invalid PES start code: "
183 << std::hex << "0x" << packet_start_code_prefix << std::dec;
184 return false;
185 }
186 int stream_id;
187 DCHECK(bit_reader.ReadBits(8, &stream_id));
188 VLOG(LOG_LEVEL_PES) << "stream_id=" << std::hex << stream_id << std::dec;
189 int pes_packet_length;
190 DCHECK(bit_reader.ReadBits(16, &pes_packet_length));
191 bool pes_packet_length_defined = (pes_packet_length != 0);
192 remaining_size -= 6;
193
194 if (stream_id != kProgramStreamMap &&
195 stream_id != kPaddingStream &&
196 stream_id != kPrivateStream2 &&
197 stream_id != kEcmStream &&
198 stream_id != kEmmStream &&
199 stream_id != kProgramStreamDirectory &&
200 stream_id != kDsmccStream &&
201 stream_id != kItu222TypeEStream) {
202 if (remaining_size < 3) {
203 return false;
204 }
205 int dummy_2;
206 DCHECK(bit_reader.ReadBits(2, &dummy_2));
207 if (dummy_2 != 0x2) {
208 LOG(WARNING) << "Unexpected bits";
209 return false;
210 }
211 int PES_scrambling_control;
212 DCHECK(bit_reader.ReadBits(2, &PES_scrambling_control));
213 bool PES_priority;
214 DCHECK(bit_reader.ReadBits(1, &PES_priority));
215 bool data_alignment_indicator;
216 DCHECK(bit_reader.ReadBits(1, &data_alignment_indicator));
217 bool copyright;
218 DCHECK(bit_reader.ReadBits(1, &copyright));
219 bool original_or_copy;
220 DCHECK(bit_reader.ReadBits(1, &original_or_copy));
221 int pts_dts_flags;
222 DCHECK(bit_reader.ReadBits(2, &pts_dts_flags));
223 bool escr_flag;
224 DCHECK(bit_reader.ReadBits(1, &escr_flag));
225 bool es_rate_flag;
226 DCHECK(bit_reader.ReadBits(1, &es_rate_flag));
227 bool dsm_trick_mode_flag;
228 DCHECK(bit_reader.ReadBits(1, &dsm_trick_mode_flag));
229 bool additional_copy_info_flag;
230 DCHECK(bit_reader.ReadBits(1, &additional_copy_info_flag));
231 bool pes_crc_flag;
232 DCHECK(bit_reader.ReadBits(1, &pes_crc_flag));
233 bool pes_extension_flag;
234 DCHECK(bit_reader.ReadBits(1, &pes_extension_flag));
235 int pes_header_data_length;
236 DCHECK(bit_reader.ReadBits(8, &pes_header_data_length));
237 remaining_size -= 3;
238 pes_packet_length -= 3;
239
240 bool is_pts_valid = false;
241 bool is_dts_valid = false;
242 int64 pts_section = 0;
243 int64 dts_section = 0;
244 if (pts_dts_flags == 0x2) {
245 if (remaining_size < 5) {
246 return false;
247 }
248 DCHECK(bit_reader.ReadBits(40, &pts_section));
249 if (((pts_section >> 36) & 0xf) != 0x2 ||
250 !IsTimestampSectionValid(pts_section)) {
251 LOG(WARNING) << "Invalid PTS section: "
252 << std::hex << "0x" << pts_section << std::dec;
253 return false;
254 }
255 is_pts_valid = true;
256 remaining_size -= 5;
257 pes_packet_length -= 5;
258 pes_header_data_length -= 5;
259 }
260
261 if (pts_dts_flags == 0x3) {
262 if (remaining_size < 10) {
263 return false;
264 }
265 DCHECK(bit_reader.ReadBits(40, &pts_section));
266 if (((pts_section >> 36) & 0xf) != 0x3 ||
267 !IsTimestampSectionValid(pts_section)) {
268 LOG(WARNING) << "Invalid PTS section: "
269 << std::hex << "0x" << pts_section << std::dec;
270 return false;
271 }
272 DCHECK(bit_reader.ReadBits(40, &dts_section));
273 if (((dts_section >> 36) & 0xf) != 0x1 ||
274 !IsTimestampSectionValid(dts_section)) {
275 LOG(WARNING) << "Invalid DTS section: "
276 << std::hex << "0x" << dts_section << std::dec;
277 return false;
278 }
279 is_pts_valid = true;
280 is_dts_valid = true;
281 remaining_size -= 10;
282 pes_packet_length -= 10;
283 pes_header_data_length -= 10;
284 }
285
286 int64 pts = 0;
287 int64 dts = 0;
288 base::TimeDelta media_pts;
289 base::TimeDelta media_dts;
290 if (is_pts_valid) {
291 pts = ConvertTimestampSectionToTimestamp(pts_section);
292 if (previous_pts_valid_) {
293 pts = UnrollTimestamp(previous_pts_, pts, 33);
294 }
295 previous_pts_ = pts;
296 previous_pts_valid_ = true;
297 media_pts = base::TimeDelta::FromMicroseconds((1000 * pts) / 90);
298 }
299
300 if (is_dts_valid) {
301 dts = ConvertTimestampSectionToTimestamp(dts_section);
302 if (previous_dts_valid_) {
303 dts = UnrollTimestamp(previous_dts_, dts, 33);
304 }
305 previous_dts_ = dts;
306 previous_dts_valid_ = true;
307 media_dts = base::TimeDelta::FromMicroseconds((1000 * dts) / 90);
308 }
309
310 // TODO(damienv): check whether we need some info
311 // from the rest of the PES packet header.
312 if (pes_header_data_length < 0) {
313 LOG(WARNING) << "Invalid PES header length";
314 return false;
315 }
316 if (pes_header_data_length > 0) {
317 if (remaining_size < pes_header_data_length) {
318 return false;
319 }
320 for (int k = 0; k < pes_header_data_length; k++) {
321 int dummy;
322 DCHECK(bit_reader.ReadBits(8, &dummy));
323 }
324 remaining_size -= pes_header_data_length;
325 pes_packet_length -= pes_header_data_length;
326 }
327
328 // Read the PES packet.
329 if (pes_packet_length_defined && pes_packet_length < 0) {
330 LOG(WARNING) << "Invalid ES length: " << pes_packet_length;
331 return false;
332 }
333 int es_size = pes_packet_length;
334 if (!pes_packet_length_defined) {
335 es_size = remaining_size;
336 }
337 VLOG(LOG_LEVEL_PES)
338 << "Emit a reassembled PES:"
339 << " size=" << es_size
340 << " pts=" << pts
341 << " dts=" << dts
342 << " data_alignment_indicator=" << data_alignment_indicator;
343
344 int dump_count = 16;
345 if (es_size < 16)
346 dump_count = es_size;
347 int es_offset = raw_pes_.size() - remaining_size;
348 VLOG(LOG_LEVEL_PES)
349 << "=> " << base::HexEncode(&raw_pes_[es_offset], dump_count);
350 if (es_parser_) {
351 es_parser_->Parse(&raw_pes_[es_offset], es_size,
352 is_pts_valid, media_pts,
353 is_dts_valid, media_dts);
354 }
355 return true;
356 }
357
358 if (stream_id == kPaddingStream) {
359 return true;
360 }
361
362 // Handle the remaining stream ids.
363 VLOG(LOG_LEVEL_PES)
364 << "PES packet:"
365 << " size=" << pes_packet_length;
366 return true;
367 }
368
369 } // namespace mpeg2ts
370 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698