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

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
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | media/filters/ffmpeg_audio_decoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
179 }
180
181 if (!buffer) {
182 decode_cb_bound.Run(kAborted, NULL);
183 return; 180 return;
184 } 181 }
185 182
186 DecodeBuffer(buffer, decode_cb_bound); 183 DecodeBuffer(buffer, decode_cb_bound);
187 } 184 }
188 185
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) { 186 void FFmpegAudioDecoder::Reset(const base::Closure& closure) {
199 DCHECK(task_runner_->BelongsToCurrentThread()); 187 DCHECK(task_runner_->BelongsToCurrentThread());
200 188
201 avcodec_flush_buffers(codec_context_.get()); 189 avcodec_flush_buffers(codec_context_.get());
202 state_ = kNormal; 190 state_ = kNormal;
203 ResetTimestampState(); 191 ResetTimestampState();
204 task_runner_->PostTask(FROM_HERE, closure); 192 task_runner_->PostTask(FROM_HERE, closure);
205 } 193 }
206 194
207 void FFmpegAudioDecoder::Stop() { 195 void FFmpegAudioDecoder::Stop() {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 // When avcodec_decode_audio4() returns 0 data. 238 // When avcodec_decode_audio4() returns 0 data.
251 // kFlushCodec -> kError: 239 // kFlushCodec -> kError:
252 // When avcodec_decode_audio4() errors out. 240 // When avcodec_decode_audio4() errors out.
253 // (any state) -> kNormal: 241 // (any state) -> kNormal:
254 // Any time Reset() is called. 242 // Any time Reset() is called.
255 243
256 // Make sure we are notified if http://crbug.com/49709 returns. Issue also 244 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
257 // occurs with some damaged files. 245 // occurs with some damaged files.
258 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { 246 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) {
259 DVLOG(1) << "Received a buffer without timestamps!"; 247 DVLOG(1) << "Received a buffer without timestamps!";
260 decode_cb.Run(kDecodeError, NULL); 248 decode_cb.Run(kDecodeError);
261 return; 249 return;
262 } 250 }
263 251
264 if (!buffer->end_of_stream() && !discard_helper_->initialized() && 252 if (!buffer->end_of_stream() && !discard_helper_->initialized() &&
265 codec_context_->codec_id == AV_CODEC_ID_VORBIS && 253 codec_context_->codec_id == AV_CODEC_ID_VORBIS &&
266 buffer->timestamp() < base::TimeDelta()) { 254 buffer->timestamp() < base::TimeDelta()) {
267 // Dropping frames for negative timestamps as outlined in section A.2 255 // 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 256 // in the Vorbis spec. http://xiph.org/vorbis/doc/Vorbis_I_spec.html
269 const int discard_frames = 257 const int discard_frames =
270 discard_helper_->TimeDeltaToFrames(-buffer->timestamp()); 258 discard_helper_->TimeDeltaToFrames(-buffer->timestamp());
271 discard_helper_->Reset(discard_frames); 259 discard_helper_->Reset(discard_frames);
272 } 260 }
273 261
274 // Transition to kFlushCodec on the first end of stream buffer.
275 if (state_ == kNormal && buffer->end_of_stream()) {
276 state_ = kFlushCodec;
277 }
278
279 if (!FFmpegDecode(buffer)) { 262 if (!FFmpegDecode(buffer)) {
280 state_ = kError; 263 state_ = kError;
281 decode_cb.Run(kDecodeError, NULL); 264 decode_cb.Run(kDecodeError);
282 return; 265 return;
283 } 266 }
284 267
285 if (queued_audio_.empty()) { 268 if (buffer->end_of_stream()) {
286 if (state_ == kFlushCodec) { 269 state_ = kDecodeFinished;
287 DCHECK(buffer->end_of_stream()); 270 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
288 state_ = kDecodeFinished;
289 decode_cb.Run(kOk, AudioBuffer::CreateEOSBuffer());
290 return;
291 }
292
293 decode_cb.Run(kNotEnoughData, NULL);
294 return;
295 } 271 }
296 272
297 decode_cb.Run(kOk, queued_audio_.front()); 273 decode_cb.Run(kOk);
298 queued_audio_.pop_front();
299 } 274 }
300 275
301 bool FFmpegAudioDecoder::FFmpegDecode( 276 bool FFmpegAudioDecoder::FFmpegDecode(
302 const scoped_refptr<DecoderBuffer>& buffer) { 277 const scoped_refptr<DecoderBuffer>& buffer) {
303 DCHECK(queued_audio_.empty());
304
305 AVPacket packet; 278 AVPacket packet;
306 av_init_packet(&packet); 279 av_init_packet(&packet);
307 if (buffer->end_of_stream()) { 280 if (buffer->end_of_stream()) {
308 packet.data = NULL; 281 packet.data = NULL;
309 packet.size = 0; 282 packet.size = 0;
310 } else { 283 } else {
311 packet.data = const_cast<uint8*>(buffer->data()); 284 packet.data = const_cast<uint8*>(buffer->data());
312 packet.size = buffer->data_size(); 285 packet.size = buffer->data_size();
313 } 286 }
314 287
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 << ", Sample Format: " << av_frame_->format << " vs " 328 << ", Sample Format: " << av_frame_->format << " vs "
356 << av_sample_format_; 329 << av_sample_format_;
357 330
358 if (config_.codec() == kCodecAAC && 331 if (config_.codec() == kCodecAAC &&
359 av_frame_->sample_rate == 2 * config_.samples_per_second()) { 332 av_frame_->sample_rate == 2 * config_.samples_per_second()) {
360 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used." 333 MEDIA_LOG(log_cb_) << "Implicit HE-AAC signalling is being used."
361 << " Please use mp4a.40.5 instead of mp4a.40.2 in" 334 << " Please use mp4a.40.5 instead of mp4a.40.2 in"
362 << " the mimetype."; 335 << " the mimetype.";
363 } 336 }
364 // This is an unrecoverable error, so bail out. 337 // This is an unrecoverable error, so bail out.
365 queued_audio_.clear();
366 av_frame_unref(av_frame_.get()); 338 av_frame_unref(av_frame_.get());
367 return false; 339 return false;
368 } 340 }
369 341
370 // Get the AudioBuffer that the data was decoded into. Adjust the number 342 // Get the AudioBuffer that the data was decoded into. Adjust the number
371 // of frames, in case fewer than requested were actually decoded. 343 // of frames, in case fewer than requested were actually decoded.
372 output = reinterpret_cast<AudioBuffer*>( 344 output = reinterpret_cast<AudioBuffer*>(
373 av_buffer_get_opaque(av_frame_->buf[0])); 345 av_buffer_get_opaque(av_frame_->buf[0]));
374 346
375 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()), 347 DCHECK_EQ(ChannelLayoutToChannelCount(config_.channel_layout()),
376 output->channel_count()); 348 output->channel_count());
377 const int unread_frames = output->frame_count() - av_frame_->nb_samples; 349 const int unread_frames = output->frame_count() - av_frame_->nb_samples;
378 DCHECK_GE(unread_frames, 0); 350 DCHECK_GE(unread_frames, 0);
379 if (unread_frames > 0) 351 if (unread_frames > 0)
380 output->TrimEnd(unread_frames); 352 output->TrimEnd(unread_frames);
381 av_frame_unref(av_frame_.get()); 353 av_frame_unref(av_frame_.get());
382 } 354 }
383 355
384 // WARNING: |av_frame_| no longer has valid data at this point. 356 // WARNING: |av_frame_| no longer has valid data at this point.
385 const int decoded_frames = frame_decoded ? output->frame_count() : 0; 357 const int decoded_frames = frame_decoded ? output->frame_count() : 0;
386 if (IsEndOfStream(result, decoded_frames, buffer)) { 358 if (IsEndOfStream(result, decoded_frames, buffer)) {
387 DCHECK_EQ(packet.size, 0); 359 DCHECK_EQ(packet.size, 0);
388 queued_audio_.push_back(AudioBuffer::CreateEOSBuffer()); 360 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
389 } else if (discard_helper_->ProcessBuffers(buffer, output)) { 361 } else if (discard_helper_->ProcessBuffers(buffer, output)) {
390 queued_audio_.push_back(output); 362 output_cb_.Run(output);
391 } 363 }
392 } while (packet.size > 0); 364 } while (packet.size > 0);
393 365
394 return true; 366 return true;
395 } 367 }
396 368
397 void FFmpegAudioDecoder::ReleaseFFmpegResources() { 369 void FFmpegAudioDecoder::ReleaseFFmpegResources() {
398 codec_context_.reset(); 370 codec_context_.reset();
399 av_frame_.reset(); 371 av_frame_.reset();
400 } 372 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 425
454 ResetTimestampState(); 426 ResetTimestampState();
455 return true; 427 return true;
456 } 428 }
457 429
458 void FFmpegAudioDecoder::ResetTimestampState() { 430 void FFmpegAudioDecoder::ResetTimestampState() {
459 discard_helper_->Reset(config_.codec_delay()); 431 discard_helper_->Reset(config_.codec_delay());
460 } 432 }
461 433
462 } // namespace media 434 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | media/filters/ffmpeg_audio_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698