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

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

Issue 339653003: No EOS frame in {Audio|Video}Decoder::OutputCB. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase only 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 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 void FFmpegAudioDecoder::DecodeBuffer( 206 void FFmpegAudioDecoder::DecodeBuffer(
207 const scoped_refptr<DecoderBuffer>& buffer, 207 const scoped_refptr<DecoderBuffer>& buffer,
208 const DecodeCB& decode_cb) { 208 const DecodeCB& decode_cb) {
209 DCHECK(task_runner_->BelongsToCurrentThread()); 209 DCHECK(task_runner_->BelongsToCurrentThread());
210 DCHECK_NE(state_, kUninitialized); 210 DCHECK_NE(state_, kUninitialized);
211 DCHECK_NE(state_, kDecodeFinished); 211 DCHECK_NE(state_, kDecodeFinished);
212 DCHECK_NE(state_, kError); 212 DCHECK_NE(state_, kError);
213 213
214 DCHECK(buffer); 214 DCHECK(buffer);
215 215
216 // During decode, because reads are issued asynchronously, it is possible to
217 // receive multiple end of stream buffers since each decode is acked. When the
218 // first end of stream buffer is read, FFmpeg may still have frames queued
219 // up in the decoder so we need to go through the decode loop until it stops
220 // giving sensible data. After that, the decoder should output empty
221 // frames. There are three states the decoder can be in:
222 //
223 // kNormal: This is the starting state. Buffers are decoded. Decode errors
224 // are discarded.
225 // kFlushCodec: There isn't any more input data. Call avcodec_decode_audio4
226 // until no more data is returned to flush out remaining
227 // frames. The input buffer is ignored at this point.
228 // kDecodeFinished: All calls return empty frames.
229 // kError: Unexpected error happened.
230 //
231 // These are the possible state transitions.
232 //
233 // kNormal -> kFlushCodec:
234 // When buffer->end_of_stream() is first true.
235 // kNormal -> kError:
236 // A decoding error occurs and decoding needs to stop.
237 // kFlushCodec -> kDecodeFinished:
238 // When avcodec_decode_audio4() returns 0 data.
239 // kFlushCodec -> kError:
240 // When avcodec_decode_audio4() errors out.
241 // (any state) -> kNormal:
242 // Any time Reset() is called.
243
244 // Make sure we are notified if http://crbug.com/49709 returns. Issue also 216 // Make sure we are notified if http://crbug.com/49709 returns. Issue also
245 // occurs with some damaged files. 217 // occurs with some damaged files.
246 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) { 218 if (!buffer->end_of_stream() && buffer->timestamp() == kNoTimestamp()) {
247 DVLOG(1) << "Received a buffer without timestamps!"; 219 DVLOG(1) << "Received a buffer without timestamps!";
248 decode_cb.Run(kDecodeError); 220 decode_cb.Run(kDecodeError);
249 return; 221 return;
250 } 222 }
251 223
252 if (!FFmpegDecode(buffer)) { 224 bool has_produced_frame;
253 state_ = kError; 225 do {
254 decode_cb.Run(kDecodeError); 226 has_produced_frame = false;
255 return; 227 if (!FFmpegDecode(buffer, &has_produced_frame)) {
256 } 228 state_ = kError;
229 decode_cb.Run(kDecodeError);
230 return;
231 }
232 // Repeat to flush the decoder after receiving EOS buffer.
233 } while (buffer->end_of_stream() && has_produced_frame);
257 234
258 if (buffer->end_of_stream()) { 235 if (buffer->end_of_stream())
259 state_ = kDecodeFinished; 236 state_ = kDecodeFinished;
260 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
261 }
262 237
263 decode_cb.Run(kOk); 238 decode_cb.Run(kOk);
264 } 239 }
265 240
266 bool FFmpegAudioDecoder::FFmpegDecode( 241 bool FFmpegAudioDecoder::FFmpegDecode(
267 const scoped_refptr<DecoderBuffer>& buffer) { 242 const scoped_refptr<DecoderBuffer>& buffer,
243 bool* has_produced_frame) {
244 DCHECK(!*has_produced_frame);
245
268 AVPacket packet; 246 AVPacket packet;
269 av_init_packet(&packet); 247 av_init_packet(&packet);
270 if (buffer->end_of_stream()) { 248 if (buffer->end_of_stream()) {
271 packet.data = NULL; 249 packet.data = NULL;
272 packet.size = 0; 250 packet.size = 0;
273 } else { 251 } else {
274 packet.data = const_cast<uint8*>(buffer->data()); 252 packet.data = const_cast<uint8*>(buffer->data());
275 packet.size = buffer->data_size(); 253 packet.size = buffer->data_size();
276 } 254 }
277 255
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 DCHECK_GE(unread_frames, 0); 318 DCHECK_GE(unread_frames, 0);
341 if (unread_frames > 0) 319 if (unread_frames > 0)
342 output->TrimEnd(unread_frames); 320 output->TrimEnd(unread_frames);
343 av_frame_unref(av_frame_.get()); 321 av_frame_unref(av_frame_.get());
344 } 322 }
345 323
346 // WARNING: |av_frame_| no longer has valid data at this point. 324 // WARNING: |av_frame_| no longer has valid data at this point.
347 const int decoded_frames = frame_decoded ? output->frame_count() : 0; 325 const int decoded_frames = frame_decoded ? output->frame_count() : 0;
348 if (IsEndOfStream(result, decoded_frames, buffer)) { 326 if (IsEndOfStream(result, decoded_frames, buffer)) {
349 DCHECK_EQ(packet.size, 0); 327 DCHECK_EQ(packet.size, 0);
350 output_cb_.Run(AudioBuffer::CreateEOSBuffer());
351 } else if (discard_helper_->ProcessBuffers(buffer, output)) { 328 } else if (discard_helper_->ProcessBuffers(buffer, output)) {
329 *has_produced_frame = true;
352 output_cb_.Run(output); 330 output_cb_.Run(output);
353 } 331 }
354 } while (packet.size > 0); 332 } while (packet.size > 0);
355 333
356 return true; 334 return true;
357 } 335 }
358 336
359 void FFmpegAudioDecoder::ReleaseFFmpegResources() { 337 void FFmpegAudioDecoder::ReleaseFFmpegResources() {
360 codec_context_.reset(); 338 codec_context_.reset();
361 av_frame_.reset(); 339 av_frame_.reset();
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 393
416 ResetTimestampState(); 394 ResetTimestampState();
417 return true; 395 return true;
418 } 396 }
419 397
420 void FFmpegAudioDecoder::ResetTimestampState() { 398 void FFmpegAudioDecoder::ResetTimestampState() {
421 discard_helper_->Reset(config_.codec_delay()); 399 discard_helper_->Reset(config_.codec_delay());
422 } 400 }
423 401
424 } // namespace media 402 } // 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