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

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

Issue 297553002: Add callback in VideoDecoder and AudioDecoder to return decoded frames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_audio_decoder.h" 5 #include "media/filters/ffmpeg_audio_decoder.h"
6 6
7 #include "base/callback_helpers.h" 7 #include "base/callback_helpers.h"
8 #include "base/single_thread_task_runner.h" 8 #include "base/single_thread_task_runner.h"
9 #include "media/base/audio_buffer.h" 9 #include "media/base/audio_buffer.h"
10 #include "media/base/audio_bus.h" 10 #include "media/base/audio_bus.h"
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 log_cb_(log_cb) { 134 log_cb_(log_cb) {
135 } 135 }
136 136
137 FFmpegAudioDecoder::~FFmpegAudioDecoder() { 137 FFmpegAudioDecoder::~FFmpegAudioDecoder() {
138 DCHECK_EQ(state_, kUninitialized); 138 DCHECK_EQ(state_, kUninitialized);
139 DCHECK(!codec_context_); 139 DCHECK(!codec_context_);
140 DCHECK(!av_frame_); 140 DCHECK(!av_frame_);
141 } 141 }
142 142
143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config, 143 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config,
144 const PipelineStatusCB& status_cb) { 144 const PipelineStatusCB& status_cb,
145 const OutputCB& output_cb) {
145 DCHECK(task_runner_->BelongsToCurrentThread()); 146 DCHECK(task_runner_->BelongsToCurrentThread());
146 DCHECK(!config.is_encrypted()); 147 DCHECK(!config.is_encrypted());
147 148
148 FFmpegGlue::InitializeFFmpeg(); 149 FFmpegGlue::InitializeFFmpeg();
149 150
150 config_ = config; 151 config_ = config;
151 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); 152 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
152 153
153 if (!config.IsValidConfig() || !ConfigureDecoder()) { 154 if (!config.IsValidConfig() || !ConfigureDecoder()) {
154 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 155 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
155 return; 156 return;
156 } 157 }
157 158
158 // Success! 159 // Success!
160 output_cb_ = BindToCurrentLoop(output_cb);
159 state_ = kNormal; 161 state_ = kNormal;
160 initialize_cb.Run(PIPELINE_OK); 162 initialize_cb.Run(PIPELINE_OK);
161 } 163 }
162 164
163 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 165 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
164 const DecodeCB& decode_cb) { 166 const DecodeCB& decode_cb) {
165 DCHECK(task_runner_->BelongsToCurrentThread()); 167 DCHECK(task_runner_->BelongsToCurrentThread());
166 DCHECK(!decode_cb.is_null()); 168 DCHECK(!decode_cb.is_null());
167 CHECK_NE(state_, kUninitialized); 169 CHECK_NE(state_, kUninitialized);
168 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); 170 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb);
169 171
170 if (state_ == kError) { 172 if (state_ == kError) {
171 decode_cb_bound.Run(kDecodeError, NULL); 173 decode_cb_bound.Run(kDecodeError);
172 return; 174 return;
173 } 175 }
174 176
175 // Return empty frames if decoding has finished. 177 // Do nothing if decoding has finished.
176 if (state_ == kDecodeFinished) { 178 if (state_ == kDecodeFinished) {
177 decode_cb_bound.Run(kOk, AudioBuffer::CreateEOSBuffer()); 179 decode_cb_bound.Run(kOk);
178 return; 180 return;
179 } 181 }
180 182
181 if (!buffer) { 183 if (!buffer) {
xhwang 2014/06/05 21:53:50 hmm, should this ever happen?
Sergey Ulanov 2014/06/06 22:49:40 Done.
182 decode_cb_bound.Run(kAborted, NULL); 184 decode_cb_bound.Run(kAborted);
183 return; 185 return;
184 } 186 }
185 187
186 DecodeBuffer(buffer, decode_cb_bound); 188 DecodeBuffer(buffer, decode_cb_bound);
187 } 189 }
188 190
189 scoped_refptr<AudioBuffer> FFmpegAudioDecoder::GetDecodeOutput() {
190 DCHECK(task_runner_->BelongsToCurrentThread());
191 if (queued_audio_.empty())
192 return NULL;
193 scoped_refptr<AudioBuffer> out = queued_audio_.front();
194 queued_audio_.pop_front();
195 return out;
196 }
197
198 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { 191 void FFmpegAudioDecoder::Reset(const base::Closure& closure) {
199 DCHECK(task_runner_->BelongsToCurrentThread()); 192 DCHECK(task_runner_->BelongsToCurrentThread());
200 193
201 avcodec_flush_buffers(codec_context_.get()); 194 avcodec_flush_buffers(codec_context_.get());
202 state_ = kNormal; 195 state_ = kNormal;
203 ResetTimestampState(); 196 ResetTimestampState();
204 task_runner_->PostTask(FROM_HERE, closure); 197 task_runner_->PostTask(FROM_HERE, closure);
205 } 198 }
206 199
207 void FFmpegAudioDecoder::Stop() { 200 void FFmpegAudioDecoder::Stop() {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 // When avcodec_decode_audio4() returns 0 data. 243 // When avcodec_decode_audio4() returns 0 data.
251 // kFlushCodec -> kError: 244 // kFlushCodec -> kError:
252 // When avcodec_decode_audio4() errors out. 245 // When avcodec_decode_audio4() errors out.
253 // (any state) -> kNormal: 246 // (any state) -> kNormal:
254 // Any time Reset() is called. 247 // Any time Reset() is called.
255 248
256 // Make sure we are notified if http://crbug.com/49709 returns. Issue also 249 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
257 // occurs with some damaged files. 250 // occurs with some damaged files.
258 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { 251 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) {
259 DVLOG(1) << "Received a buffer without timestamps!"; 252 DVLOG(1) << "Received a buffer without timestamps!";
260 decode_cb.Run(kDecodeError, NULL); 253 decode_cb.Run(kDecodeError);
261 return; 254 return;
262 } 255 }
263 256
264 if (!buffer->end_of_stream() && !discard_helper_->initialized() && 257 if (!buffer->end_of_stream() && !discard_helper_->initialized() &&
265 codec_context_->codec_id == AV_CODEC_ID_VORBIS && 258 codec_context_->codec_id == AV_CODEC_ID_VORBIS &&
266 buffer->timestamp() < base::TimeDelta()) { 259 buffer->timestamp() < base::TimeDelta()) {
267 // Dropping frames for negative timestamps as outlined in section A.2 260 // Dropping frames for negative timestamps as outlined in section A.2
268 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html 261 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html
269 const int discard_frames = 262 const int discard_frames =
270 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); 263 discard_helper_->TimeDeltaToFrames(-buffer->timestamp());
271 discard_helper_->Reset(discard_frames); 264 discard_helper_->Reset(discard_frames);
272 } 265 }
273 266
274 // Transition to kFlushCodec on the first end of stream buffer. 267 // Transition to kFlushCodec on the first end of stream buffer.
275 if (state_ == kNormal && buffer->end_of_stream()) { 268 if (state_ == kNormal && buffer->end_of_stream()) {
276 state_ = kFlushCodec; 269 state_ = kFlushCodec;
277 } 270 }
278 271
279 if (!FFmpegDecode(buffer)) { 272 if (!FFmpegDecode(buffer)) {
280 state_ = kError; 273 state_ = kError;
281 decode_cb.Run(kDecodeError, NULL); 274 decode_cb.Run(kDecodeError);
282 return; 275 return;
283 } 276 }
284 277
285 if (queued_audio_.empty()) { 278 if (state_ == kFlushCodec) {
286 if (state_ == kFlushCodec) { 279 state_ = kDecodeFinished;
287 DCHECK(buffer->end_of_stream()); 280 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
xhwang 2014/06/05 21:53:50 should we keep calling FFmpegDecode(EOS) until the
Sergey Ulanov 2014/06/06 22:49:40 There is a loop in FFmpegDecode() which should flu
288 state_ = kDecodeFinished;
289 decode_cb.Run(kOk, AudioBuffer::CreateEOSBuffer());
290 return;
291 }
292
293 decode_cb.Run(kNotEnoughData, NULL);
294 return;
295 } 281 }
296 282
297 decode_cb.Run(kOk, queued_audio_.front()); 283 decode_cb.Run(kOk);
298 queued_audio_.pop_front();
299 } 284 }
300 285
301 bool FFmpegAudioDecoder::FFmpegDecode( 286 bool FFmpegAudioDecoder::FFmpegDecode(
302 const scoped_refptr<DecoderBuffer>& buffer) { 287 const scoped_refptr<DecoderBuffer>& buffer) {
303 DCHECK(queued_audio_.empty());
304
305 AVPacket packet; 288 AVPacket packet;
306 av_init_packet(&packet); 289 av_init_packet(&packet);
307 if (buffer->end_of_stream()) { 290 if (buffer->end_of_stream()) {
308 packet.data = NULL; 291 packet.data = NULL;
309 packet.size = 0; 292 packet.size = 0;
310 } else { 293 } else {
311 packet.data = const_cast<uint8*>(buffer->data()); 294 packet.data = const_cast<uint8*>(buffer->data());
312 packet.size = buffer->data_size(); 295 packet.size = buffer->data_size();
313 } 296 }
314 297
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 << ", Sample Format: " << av_frame_->format << " vs " 338 << ", Sample Format: " << av_frame_->format << " vs "
356 << av_sample_format_; 339 << av_sample_format_;
357 340
358 if (config_.codec() == kCodecAAC && 341 if (config_.codec() == kCodecAAC &&
359 av_frame_->sample_rate == 2 * config_.samples_per_second()) { 342 av_frame_->sample_rate == 2 * config_.samples_per_second()) {
360 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." 343 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used."
361 << " Please use mp4a.40.5 instead of mp4a.40.2 in" 344 << " Please use mp4a.40.5 instead of mp4a.40.2 in"
362 << " the mimetype."; 345 << " the mimetype.";
363 } 346 }
364 // This is an unrecoverable error, so bail out. 347 // This is an unrecoverable error, so bail out.
365 queued_audio_.clear();
366 av_frame_unref(av_frame_.get()); 348 av_frame_unref(av_frame_.get());
367 return false; 349 return false;
368 } 350 }
369 351
370 // Get the AudioBuffer that the data was decoded into. Adjust the number 352 // Get the AudioBuffer that the data was decoded into. Adjust the number
371 // of frames, in case fewer than requested were actually decoded. 353 // of frames, in case fewer than requested were actually decoded.
372 output = reinterpret_cast<AudioBuffer*>( 354 output = reinterpret_cast<AudioBuffer*>(
373 av_buffer_get_opaque(av_frame_->buf[0])); 355 av_buffer_get_opaque(av_frame_->buf[0]));
374 356
375 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), 357 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()),
376 output->channel_count()); 358 output->channel_count());
377 const int unread_frames = output->frame_count() - av_frame_->nb_samples; 359 const int unread_frames = output->frame_count() - av_frame_->nb_samples;
378 DCHECK_GE(unread_frames, 0); 360 DCHECK_GE(unread_frames, 0);
379 if (unread_frames > 0) 361 if (unread_frames > 0)
380 output->TrimEnd(unread_frames); 362 output->TrimEnd(unread_frames);
381 363
382 av_frame_unref(av_frame_.get()); 364 av_frame_unref(av_frame_.get());
383 } 365 }
384 366
385 // WARNING: |av_frame_| no longer has valid data at this point. 367 // WARNING: |av_frame_| no longer has valid data at this point.
386 const int decoded_frames = frame_decoded ? output->frame_count() : 0; 368 const int decoded_frames = frame_decoded ? output->frame_count() : 0;
387 if (IsEndOfStream(result, decoded_frames, buffer)) { 369 if (IsEndOfStream(result, decoded_frames, buffer)) {
388 DCHECK_EQ(packet.size, 0); 370 DCHECK_EQ(packet.size, 0);
389 queued_audio_.push_back(AudioBuffer::CreateEOSBuffer()); 371 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
390 } else if (discard_helper_->ProcessBuffers(buffer, output)) { 372 } else if (discard_helper_->ProcessBuffers(buffer, output)) {
391 queued_audio_.push_back(output); 373 output_cb_.Run(output);
392 } 374 }
393 } while (packet.size > 0); 375 } while (packet.size > 0);
394 376
395 return true; 377 return true;
396 } 378 }
397 379
398 void FFmpegAudioDecoder::ReleaseFFmpegResources() { 380 void FFmpegAudioDecoder::ReleaseFFmpegResources() {
399 codec_context_.reset(); 381 codec_context_.reset();
400 av_frame_.reset(); 382 av_frame_.reset();
401 } 383 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 436
455 ResetTimestampState(); 437 ResetTimestampState();
456 return true; 438 return true;
457 } 439 }
458 440
459 void FFmpegAudioDecoder::ResetTimestampState() { 441 void FFmpegAudioDecoder::ResetTimestampState() {
460 discard_helper_->Reset(config_.codec_delay()); 442 discard_helper_->Reset(config_.codec_delay());
461 } 443 }
462 444
463 } // namespace media 445 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698