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

Side by Side Diff: media/filters/opus_audio_decoder.cc

Issue 11416367: Add Opus decode wrapper to media. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Move opus support behind a flag, and add canPlayType support. Created 8 years 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 | Annotate | Revision Log
OLDNEW
(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 "media/filters/opus_audio_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/message_loop_proxy.h"
11 #include "base/sys_byteorder.h"
12 #include "media/base/audio_decoder_config.h"
13 #include "media/base/audio_timestamp_helper.h"
14 #include "media/base/data_buffer.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/demuxer.h"
17 #include "media/base/pipeline.h"
18 #include "third_party/opus/src/include/opus.h"
19 #include "third_party/opus/src/include/opus_multistream.h"
20
21 namespace media {
22
23 static uint16 ReadLE16(const uint8* data, size_t data_size, int read_offset) {
24 DCHECK(data);
25 DCHECK_LE(read_offset + sizeof(uint16), data_size);
26 return base::ByteSwapToLE16(
27 *reinterpret_cast<const uint16*>((data + read_offset)));
xhwang 2012/12/13 08:33:13 This is not safe: http://code.google.com/searchfra
fgalligan1 2012/12/13 22:30:14 This should be fine as long as the size of the dat
Tom Finegan 2012/12/13 23:20:00 Done.
xhwang 2012/12/14 01:19:21 Type punning is about "holding an object in memory
28 }
29
30 // Helper structure for managing multiple decoded audio frames per packet.
31 struct QueuedAudioBuffer {
32 AudioDecoder::Status status;
33 scoped_refptr<Buffer> buffer;
34 };
35
36 // Returns true if the decode result was end of stream.
37 static inline bool IsEndOfStream(int decoded_size, Buffer* input) {
38 // Two conditions to meet to declare end of stream for this decoder:
39 // 1. Opus didn't output anything.
40 // 2. An end of stream buffer is received.
41 return decoded_size == 0 && input->IsEndOfStream();
42 }
43
44 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
45 // mappings for up to 8 channels. See section 4.3.9 of the vorbis
46 // specification:
47 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
48 static const int kMaxVorbisChannels = 8;
49
50 // Opus allows for decode of S16 or float samples. OpusAudioDecoder always uses
51 // S16 samples.
52 static const int kRequiredSampleSize = 16;
53 static const int kBytesPerChannel = kRequiredSampleSize / 2;
xhwang 2012/12/13 08:33:13 why 2? It's not obvious to me...
Tom Finegan 2012/12/13 23:20:00 Sleep deprived... 2's the result I want, should ha
54
55 // Maximum packet size used in Xiph's opusdec and FFmpeg's libopusdec.
56 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
xhwang 2012/12/13 08:33:13 Could you add a link to the spec?
Tom Finegan 2012/12/13 23:20:00 Done, but it's up a little higher in the file.
57 static const int kMaxOpusOutputPacketSizeBytes =
58 kMaxOpusOutputPacketSizeSamples * kBytesPerChannel;
59
60 static bool RemapOpusChannelLayout(const uint8* opus_mapping,
61 int num_channels,
62 uint8* channel_layout) {
63 DCHECK(opus_mapping);
64 DCHECK(channel_layout);
65 DCHECK_LE(num_channels, kMaxVorbisChannels);
66 if (!channel_layout || num_channels > kMaxVorbisChannels)
67 return false;
68
69 // Opus uses Vorbis channel layout.
70 const int32 num_layouts = kMaxVorbisChannels;
71 const int32 num_layout_values = kMaxVorbisChannels;
72 const uint8 kVorbisChannelLayouts[num_layouts][num_layout_values] = {
73 { 0 },
74 { 0, 1 },
75 { 0, 2, 1 },
76 { 0, 1, 2, 3 },
77 { 0, 2, 1, 3, 4 },
78 { 0, 2, 1, 5, 3, 4 },
79 { 0, 2, 1, 6, 5, 3, 4 },
80 { 0, 2, 1, 7, 5, 6, 3, 4 },
81 };
82
83 const uint8* vorbis_layout_offset = kVorbisChannelLayouts[num_channels - 1];
84 for (int channel = 0; channel < num_channels; ++channel)
85 channel_layout[channel] = opus_mapping[vorbis_layout_offset[channel]];
86
87 return true;
88 }
89
90 // Opus Header contents:
91 // - "OpusHead" (64 bits)
92 // - version number (8 bits)
93 // - Channels C (8 bits)
94 // - Pre-skip (16 bits)
95 // - Sampling rate (32 bits)
96 // - Gain in dB (16 bits, S7.8)
97 // - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,
98 // 2..254: reserved, 255: multistream with no mapping)
99 //
100 // - if (mapping != 0)
101 // - N = totel number of streams (8 bits)
102 // - M = number of paired streams (8 bits)
103 // - C times channel origin
104 // - if (C<2*M)
105 // - stream = byte/2
106 // - if (byte&0x1 == 0)
107 // - left
108 // else
109 // - right
110 // - else
111 // - stream = byte-M
112
113 // Default audio output channel layout. Used to initialize |stream_map| in
114 // OpusHeader, and passed to |opus_multistream_decoder_create()| when the
115 // header does not contain mapping information.
116 static const uint8 kDefaultOpusChannelLayout[kMaxVorbisChannels] = {
117 0, 1, 0, 0, 0, 0, 0, 0 };
xhwang 2012/12/13 08:33:13 what are these values? are they indices into kVorb
Tom Finegan 2012/12/13 23:20:00 The values are what the comment says: The default
118
119 // Size of the Opus header excluding optional mapping information.
120 static const int kOpusHeaderSize = 19;
121
122 // Offset to the channel count byte in the Opus header.
123 static const int kOpusHeaderChannelsOffset = 9;
124
125 // Offset to the pre-skip value in the Opus header.
126 static const int kOpusHeaderSkipSamplesOffset = 10;
127
128 // Offset to the channel mapping byte in the Opus header.
129 static const int kOpusHeaderChannelMappingOffset = 18;
130
131 struct OpusHeader {
132 OpusHeader()
133 : channels(0),
134 skip_samples(0),
135 channel_mapping(0),
136 num_streams(0),
137 num_coupled(0) {
138 memcpy(&stream_map[0], &kDefaultOpusChannelLayout[0], kMaxVorbisChannels);
xhwang 2012/12/13 08:33:13 can this be memcpy(stream_map, kDefaultOpusChannel
Tom Finegan 2012/12/13 23:20:00 Done. Was just being over explicit, I guess. :)
139 }
140 int channels;
141 int skip_samples;
142 int channel_mapping;
143 int num_streams;
144 int num_coupled;
145 uint8 stream_map[kMaxVorbisChannels];
146 };
147
148 // Returns true when able to successfully parse and store Opus header data in
149 // data parsed in |header|. Based on opus header parsing code in libopusdec
150 // from FFmpeg, and opus_header from Xiph's opus-tools project.
151 static bool ParseOpusHeader(const uint8* data, int data_size,
152 const AudioDecoderConfig& config,
153 OpusHeader* header) {
154 DCHECK(data);
155 DCHECK(header);
156 DCHECK_GE(data_size, kOpusHeaderSize);
157
158 if (!data || data_size < kOpusHeaderSize || !header)
159 return false;
160
161 header->channels = *(data + kOpusHeaderChannelsOffset);
162
163 DCHECK(header->channels > 0 && header->channels <= kMaxVorbisChannels);
164 if (header->channels <= 0 || header->channels > kMaxVorbisChannels) {
165 LOG(ERROR) << "ParseOpusHeader(): invalid channel count in header "
166 << ChannelLayoutToChannelCount(config.channel_layout());
167 return false;
168 }
169
170 header->skip_samples =
171 ReadLE16(data, data_size, kOpusHeaderSkipSamplesOffset);
172
173 header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
174
175 if (header->channels > 2 && !header->channel_mapping) {
176 LOG(ERROR) << "ParseOpusHeader(): Invalid header, missing stream map.";
177 return false;
178 }
179
180 if (header->channel_mapping) {
181 const int mapping_required_size =
182 kOpusHeaderSize + kBytesPerChannel + header->channels;
183 if (data_size < mapping_required_size) {
184 LOG(ERROR) << "ParseOpusHeader(): Invalid stream map.";
185 return false;
186 }
187
188 // Header contains a stream map. The mapping values are in extra data
189 // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
190 // data contains stream count, coupling information, and per channel
191 // mapping values:
192 // - Byte 0: Number of streams.
193 // - Byte 1: Number coupled.
194 // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
195 // values.
196 header->num_streams = *(data + kOpusHeaderSize);
xhwang 2012/12/13 08:33:13 Can we actually have kOpusHeaderNumStreamsOffset,
Tom Finegan 2012/12/13 23:20:00 Done.
197 header->num_coupled = *(data + kOpusHeaderSize + 1);
198
199 if (header->num_streams + header->num_coupled != header->channels)
200 LOG(WARNING) << "ParseOpusHeader(): Inconsistent channel mapping.";
201
202 for (int i = 0; i < kMaxVorbisChannels; ++i)
203 header->stream_map[i] = *(data + kOpusHeaderSize + kBytesPerChannel + i);
204 } else {
205 header->num_streams = 1;
206 header->num_coupled =
207 (ChannelLayoutToChannelCount(config.channel_layout()) > 1) ? 1 : 0;
208 }
209
210 return true;
xhwang 2012/12/13 08:33:13 nit: I like return early and avoid large if/else b
Tom Finegan 2012/12/13 23:20:00 Done.
211 }
212
213 OpusAudioDecoder::OpusAudioDecoder(
214 const scoped_refptr<base::MessageLoopProxy>& message_loop)
215 : message_loop_(message_loop),
216 opus_decoder_(NULL),
217 bits_per_channel_(0),
218 channel_layout_(CHANNEL_LAYOUT_NONE),
219 samples_per_second_(0),
220 last_input_timestamp_(kNoTimestamp()),
221 output_bytes_to_drop_(0) {
222 }
223
224 void OpusAudioDecoder::Initialize(
225 const scoped_refptr<DemuxerStream>& stream,
226 const PipelineStatusCB& status_cb,
227 const StatisticsCB& statistics_cb) {
228 if (!message_loop_->BelongsToCurrentThread()) {
229 message_loop_->PostTask(FROM_HERE, base::Bind(
xhwang 2012/12/13 08:33:13 FYI, the 2013 fashion trend shows that we are remo
Tom Finegan 2012/12/13 23:20:00 Ok.
230 &OpusAudioDecoder::DoInitialize, this,
231 stream, status_cb, statistics_cb));
232 return;
233 }
234 DoInitialize(stream, status_cb, statistics_cb);
235 }
236
237 void OpusAudioDecoder::Read(const ReadCB& read_cb) {
238 // Complete operation asynchronously on different stack of execution as per
239 // the API contract of AudioDecoder::Read()
240 message_loop_->PostTask(FROM_HERE, base::Bind(
241 &OpusAudioDecoder::DoRead, this, read_cb));
242 }
243
244 int OpusAudioDecoder::bits_per_channel() {
245 return bits_per_channel_;
246 }
247
248 ChannelLayout OpusAudioDecoder::channel_layout() {
249 return channel_layout_;
250 }
251
252 int OpusAudioDecoder::samples_per_second() {
253 return samples_per_second_;
254 }
255
256 void OpusAudioDecoder::Reset(const base::Closure& closure) {
257 message_loop_->PostTask(FROM_HERE, base::Bind(
258 &OpusAudioDecoder::DoReset, this, closure));
259 }
260
261 OpusAudioDecoder::~OpusAudioDecoder() {
262 // TODO(scherkus): should we require Stop() to be called? this might end up
263 // getting called on a random thread due to refcounting.
264 CloseDecoder();
265 }
266
267 void OpusAudioDecoder::DoInitialize(
268 const scoped_refptr<DemuxerStream>& stream,
269 const PipelineStatusCB& status_cb,
270 const StatisticsCB& statistics_cb) {
271 if (demuxer_stream_) {
272 // TODO(scherkus): initialization currently happens more than once in
273 // PipelineIntegrationTest.BasicPlayback.
274 LOG(ERROR) << "Initialize has already been called.";
275 CHECK(false);
276 }
277
278 demuxer_stream_ = stream;
279
280 if (!ConfigureDecoder()) {
281 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
282 return;
283 }
284
285 statistics_cb_ = statistics_cb;
286 status_cb.Run(PIPELINE_OK);
287 }
288
289 void OpusAudioDecoder::DoReset(const base::Closure& closure) {
290 opus_multistream_decoder_ctl(opus_decoder_, OPUS_RESET_STATE);
291 ResetTimestampState();
292 queued_audio_.clear();
293 closure.Run();
294 }
295
296 void OpusAudioDecoder::DoRead(const ReadCB& read_cb) {
297 DCHECK(message_loop_->BelongsToCurrentThread());
298 DCHECK(!read_cb.is_null());
299 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
300
301 read_cb_ = read_cb;
302
303 // If we don't have any queued audio from the last packet we decoded, ask for
304 // more data from the demuxer to satisfy this read.
305 if (queued_audio_.empty()) {
306 ReadFromDemuxerStream();
307 return;
308 }
309
310 base::ResetAndReturn(&read_cb_).Run(
311 queued_audio_.front().status, queued_audio_.front().buffer);
312 queued_audio_.pop_front();
313 }
314
315 void OpusAudioDecoder::DoDecodeBuffer(
316 DemuxerStream::Status status,
317 const scoped_refptr<DecoderBuffer>& input) {
318 if (!message_loop_->BelongsToCurrentThread()) {
319 message_loop_->PostTask(FROM_HERE, base::Bind(
320 &OpusAudioDecoder::DoDecodeBuffer, this, status, input));
321 return;
322 }
323
324 DCHECK(!read_cb_.is_null());
325 DCHECK(queued_audio_.empty());
326 DCHECK_EQ(status != DemuxerStream::kOk, !input) << status;
327
328 if (status == DemuxerStream::kAborted) {
329 DCHECK(!input);
330 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
331 return;
332 }
333
334 if (status == DemuxerStream::kConfigChanged) {
335 DCHECK(!input);
336
337 // Send a "end of stream" buffer to the decode loop
338 // to output any remaining data still in the decoder.
339 if (!Decode(DecoderBuffer::CreateEOSBuffer(), true)) {
340 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
341 return;
342 }
343
344 DVLOG(1) << "Config changed.";
345
346 if (!ConfigureDecoder()) {
347 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
348 return;
349 }
350
351 ResetTimestampState();
352
353 if (queued_audio_.empty()) {
354 ReadFromDemuxerStream();
355 return;
356 }
357
358 base::ResetAndReturn(&read_cb_).Run(
359 queued_audio_.front().status, queued_audio_.front().buffer);
360 queued_audio_.pop_front();
361 return;
362 }
363
364 DCHECK_EQ(status, DemuxerStream::kOk);
365 DCHECK(input);
366
367 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
368 // occurs with some damaged files.
369 if (!input->IsEndOfStream() && input->GetTimestamp() == kNoTimestamp() &&
370 output_timestamp_helper_->base_timestamp() == kNoTimestamp()) {
371 DVLOG(1) << "Received a buffer without timestamps!";
372 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
373 return;
374 }
375
376 if (!input->IsEndOfStream()) {
377 if (last_input_timestamp_ == kNoTimestamp())
378 last_input_timestamp_ = input->GetTimestamp();
379 else if (input->GetTimestamp() != kNoTimestamp()) {
380 if (input->GetTimestamp() < last_input_timestamp_) {
381 base::TimeDelta diff = input->GetTimestamp() - last_input_timestamp_;
382 DVLOG(1) << "Input timestamps are not monotonically increasing! "
383 << " ts " << input->GetTimestamp().InMicroseconds() << " us"
384 << " diff " << diff.InMicroseconds() << " us";
385 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
386 return;
387 }
388
389 last_input_timestamp_ = input->GetTimestamp();
390 }
391 }
392
393 if (!Decode(input, false)) {
394 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
395 return;
396 }
397
398 // We exhausted the provided packet, but it wasn't enough for a frame. Ask
399 // for more data in order to fulfill this read.
400 if (queued_audio_.empty()) {
401 ReadFromDemuxerStream();
402 return;
403 }
404
405 // Execute callback to return the first frame we decoded.
406 base::ResetAndReturn(&read_cb_).Run(
407 queued_audio_.front().status, queued_audio_.front().buffer);
408 queued_audio_.pop_front();
409 }
410
411 void OpusAudioDecoder::ReadFromDemuxerStream() {
412 DCHECK(!read_cb_.is_null());
413
414 demuxer_stream_->Read(base::Bind(&OpusAudioDecoder::DoDecodeBuffer, this));
415 }
416
417 bool OpusAudioDecoder::ConfigureDecoder() {
418 const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config();
419
420 if (config.codec() != kCodecOpus) {
421 DLOG(ERROR) << "ConfigureDecoder(): codec must be kCodecOpus.";
422 return false;
423 }
424
425 const int channel_count =
426 ChannelLayoutToChannelCount(config.channel_layout());
427 if (!config.IsValidConfig() || channel_count > kMaxVorbisChannels) {
428 DLOG(ERROR) << "ConfigureDecoder(): Invalid or unsupported audio stream -"
429 << " codec: " << config.codec()
430 << " channel count: " << channel_count
431 << " channel layout: " << config.channel_layout()
432 << " bits per channel: " << config.bits_per_channel()
433 << " samples per second: " << config.samples_per_second();
434 return false;
435 }
436
437 if (config.bits_per_channel() != kRequiredSampleSize) {
438 DLOG(ERROR) << "ConfigureDecoder(): 16 bit samples required.";
439 return false;
440 }
441
442 if (config.is_encrypted()) {
443 DLOG(ERROR) << "ConfigureDecoder(): Encrypted audio stream not supported.";
444 return false;
445 }
446
447 if (opus_decoder_ &&
448 (bits_per_channel_ != config.bits_per_channel() ||
449 channel_layout_ != config.channel_layout() ||
450 samples_per_second_ != config.samples_per_second())) {
xhwang 2012/12/13 08:33:13 hmm, I wonder what config change we support?
Tom Finegan 2012/12/13 23:20:00 I don't know-- this is copied from the FFmpeg deco
xhwang 2012/12/14 01:19:21 ok, thanks for letting me know.
451 DVLOG(1) << "Unsupported config change :";
452 DVLOG(1) << "\tbits_per_channel : " << bits_per_channel_
453 << " -> " << config.bits_per_channel();
454 DVLOG(1) << "\tchannel_layout : " << channel_layout_
455 << " -> " << config.channel_layout();
456 DVLOG(1) << "\tsample_rate : " << samples_per_second_
457 << " -> " << config.samples_per_second();
458 return false;
459 }
460
461 // Clean up existing decoder if necessary.
462 CloseDecoder();
463
464 // Allocate the output buffer if necessary.
465 if (!output_buffer_)
466 output_buffer_.reset(new uint8[kMaxOpusOutputPacketSizeBytes]);
467
468 // Parse the Opus header.
469 OpusHeader opus_header;
470 if (!ParseOpusHeader(config.extra_data(), config.extra_data_size(),
471 config,
472 &opus_header)) {
473 LOG(ERROR) << "ConfigureDecoder(): cannot parse opus header.";
474 return false;
475 }
476
477 skip_samples_ = opus_header.skip_samples;
478
479 if (skip_samples_ > 0)
480 output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame();
481
482 std::vector<uint8> channel_mapping(
483 &kDefaultOpusChannelLayout[0],
484 &kDefaultOpusChannelLayout[kMaxVorbisChannels - 1]);
xhwang 2012/12/13 08:33:13 Range constructor of std::vector takes [first, las
fgalligan1 2012/12/13 22:30:14 That should work.
Tom Finegan 2012/12/13 23:20:00 Removed vector.
485
486 if (channel_count > 2) {
487 // Remap channels from Vorbis order to FFmpeg order (which I what I think
fgalligan1 2012/12/13 22:30:14 which is what...
Tom Finegan 2012/12/13 23:20:00 Removed comment here, and added one up in RemapOpu
488 // we want).
489 if (!RemapOpusChannelLayout(&opus_header.stream_map[0],
490 channel_count,
491 &channel_mapping[0])) {
492 LOG(ERROR) << "ConfigureDecoder(): unable to remap opus channels.";
493 return false;
494 }
495 }
496
497 // Init Opus.
498 int status = 0;
xhwang 2012/12/13 08:33:13 looks like OPUS_OK is 0 (http://dxr.mozilla.org/mo
Tom Finegan 2012/12/13 23:20:00 Done.
499 opus_decoder_ = opus_multistream_decoder_create(config.samples_per_second(),
500 channel_count,
501 opus_header.num_streams,
502 opus_header.num_coupled,
503 &channel_mapping[0],
xhwang 2012/12/13 08:33:13 hmm, if we always use &channel_mapping[0], why do
Tom Finegan 2012/12/13 23:20:00 Why do I try to over complicate things... Done.
504 &status);
xhwang 2012/12/13 08:33:13 do we want to check if status == OPUS_OK ?
Tom Finegan 2012/12/13 23:20:00 Done.
505 if (!opus_decoder_) {
506 LOG(ERROR) << "ConfigureDecoder(): opus_multistream_decoder_create failed"
507 << " status=" << opus_strerror(status);
508 return false;
509 }
510
511 // TODO(tomfinegan): The OPUS_GET_LOOKAHEAD ctl fails with a not implemented
fgalligan1 2012/12/13 22:30:14 opus dec just sets 80 milliseconds, which is what
Tom Finegan 2012/12/13 23:20:00 Done.
512 // error code (-5). Not sure how to calculate delay....
513 // // Get audio delay from Opus.
514 // status = opus_multistream_decoder_ctl(opus_decoder_,
515 // OPUS_GET_LOOKAHEAD(&delay_));
516 // if (status != OPUS_OK) {
517 // LOG(ERROR) << "ConfigureDecoder(): cannot read audio delay from Opus.";
518 // return false;
519 // }
520
521 bits_per_channel_ = config.bits_per_channel();
522 channel_layout_ = config.channel_layout();
523 samples_per_second_ = config.samples_per_second();
524 output_timestamp_helper_.reset(new AudioTimestampHelper(
525 config.bytes_per_frame(), config.samples_per_second()));
526 return true;
527 }
528
529 void OpusAudioDecoder::CloseDecoder() {
530 if (opus_decoder_) {
531 opus_multistream_decoder_destroy(opus_decoder_);
532 opus_decoder_ = NULL;
533 }
534 }
535
536 void OpusAudioDecoder::ResetTimestampState() {
537 output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp());
538 last_input_timestamp_ = kNoTimestamp();
539 output_bytes_to_drop_ = 0;
540 }
541
542 bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input,
543 bool skip_eos_append) {
544 int16* output_buffer = reinterpret_cast<int16*>(&output_buffer_[0]);
xhwang 2012/12/13 08:33:13 This may also not be safe for type punning. It dep
fgalligan1 2012/12/13 22:30:14 Again this should be safe. But if you can change o
Tom Finegan 2012/12/13 23:20:00 Done.
545 int samples_decoded =
546 opus_multistream_decode(opus_decoder_,
547 input->GetData(), input->GetDataSize(),
548 output_buffer, kMaxOpusOutputPacketSizeSamples,
549 0);
550 if (samples_decoded < 0) {
551 DCHECK(!input->IsEndOfStream())
552 << "Decode(): End of stream buffer produced an error!";
553
554 LOG(ERROR) << "ConfigureDecoder(): opus_multistream_decode failed for"
555 << " timestamp: " << input->GetTimestamp().InMicroseconds()
556 << " us, duration: " << input->GetDuration().InMicroseconds()
557 << " us, packet size: " << input->GetDataSize() << " bytes with"
558 << " status: " << opus_strerror(samples_decoded);
559 return false;
560 }
561
562 uint8* decoded_audio_data = &output_buffer_[0];
563 int decoded_audio_size = samples_decoded *
564 demuxer_stream_->audio_decoder_config().bytes_per_frame();
565 DCHECK_LE(decoded_audio_size, kMaxOpusOutputPacketSizeBytes);
566
567 if (output_timestamp_helper_->base_timestamp() == kNoTimestamp() &&
568 !input->IsEndOfStream()) {
569 DCHECK(input->GetTimestamp() != kNoTimestamp());
570 output_timestamp_helper_->SetBaseTimestamp(input->GetTimestamp());
571 }
572
573 scoped_refptr<DataBuffer> output;
574
575 if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) {
576 int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_);
577 decoded_audio_data += dropped_size;
xhwang 2012/12/13 08:33:13 wondering if dropped_size is always a multiple of
Tom Finegan 2012/12/13 23:20:00 Added a DCHECK.
578 decoded_audio_size -= dropped_size;
579 output_bytes_to_drop_ -= dropped_size;
580 }
581
582 if (decoded_audio_size > 0) {
583 // Copy the audio samples into an output buffer.
584 output = new DataBuffer(decoded_audio_data, decoded_audio_size);
585 output->SetTimestamp(output_timestamp_helper_->GetTimestamp());
586 output->SetDuration(
587 output_timestamp_helper_->GetDuration(decoded_audio_size));
588 output_timestamp_helper_->AddBytes(decoded_audio_size);
589 } else if (IsEndOfStream(decoded_audio_size, input) && !skip_eos_append) {
590 DCHECK_EQ(input->GetDataSize(), 0);
591 // Create an end of stream output buffer.
592 output = new DataBuffer(0);
593 }
594
595 if (output) {
596 QueuedAudioBuffer queue_entry = { kOk, output };
597 queued_audio_.push_back(queue_entry);
xhwang 2012/12/13 08:33:13 queued_audio_ is used in FFmepgAudioDecoder becaus
Tom Finegan 2012/12/13 23:20:00 Ok. Wasn't sure if the pipeline consumed all outpu
598 }
599
600 // Decoding finished successfully, update statistics.
601 PipelineStatistics statistics;
602 statistics.audio_bytes_decoded = decoded_audio_size;
603 statistics_cb_.Run(statistics);
604
605 return true;
606 }
607
608 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698