| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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_video_decoder.h" | 5 #include "media/filters/ffmpeg_video_decoder.h" |
| 6 | 6 |
| 7 #include <deque> |
| 8 |
| 9 #include "base/task.h" |
| 10 #include "media/base/filters.h" |
| 11 #include "media/base/limits.h" |
| 7 #include "media/base/media_format.h" | 12 #include "media/base/media_format.h" |
| 8 #include "media/ffmpeg/ffmpeg_common.h" // For kFFmpegVideo. | 13 #include "media/base/video_frame.h" |
| 14 #include "media/ffmpeg/ffmpeg_common.h" |
| 15 #include "media/ffmpeg/ffmpeg_util.h" |
| 16 #include "media/filters/ffmpeg_interfaces.h" |
| 9 #include "media/filters/ffmpeg_video_decode_engine.h" | 17 #include "media/filters/ffmpeg_video_decode_engine.h" |
| 18 #include "media/filters/video_decode_engine.h" |
| 10 | 19 |
| 11 namespace media { | 20 namespace media { |
| 12 | 21 |
| 13 FFmpegVideoDecoder::FFmpegVideoDecoder(FFmpegVideoDecodeEngine* engine) | 22 FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeEngine* engine) |
| 14 : VideoDecoderImpl(engine) { | 23 : width_(0), |
| 24 height_(0), |
| 25 time_base_(new AVRational()), |
| 26 state_(kNormal), |
| 27 decode_engine_(engine) { |
| 15 } | 28 } |
| 16 | 29 |
| 17 FFmpegVideoDecoder::~FFmpegVideoDecoder() { | 30 FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
| 18 } | 31 } |
| 19 | 32 |
| 33 void FFmpegVideoDecoder::DoInitialize(DemuxerStream* demuxer_stream, |
| 34 bool* success, |
| 35 Task* done_cb) { |
| 36 AutoTaskRunner done_runner(done_cb); |
| 37 *success = false; |
| 38 |
| 39 // Get the AVStream by querying for the provider interface. |
| 40 AVStreamProvider* av_stream_provider; |
| 41 if (!demuxer_stream->QueryInterface(&av_stream_provider)) { |
| 42 return; |
| 43 } |
| 44 AVStream* av_stream = av_stream_provider->GetAVStream(); |
| 45 |
| 46 time_base_->den = av_stream->r_frame_rate.num; |
| 47 time_base_->num = av_stream->r_frame_rate.den; |
| 48 |
| 49 // TODO(ajwong): We don't need these extra variables if |media_format_| has |
| 50 // them. Remove. |
| 51 width_ = av_stream->codec->width; |
| 52 height_ = av_stream->codec->height; |
| 53 if (width_ > Limits::kMaxDimension || |
| 54 height_ > Limits::kMaxDimension || |
| 55 (width_ * height_) > Limits::kMaxCanvas) { |
| 56 return; |
| 57 } |
| 58 |
| 59 // Only set kMimeType when derived class has not done so. |
| 60 if (!media_format_.Contains(MediaFormat::kMimeType)) |
| 61 media_format_.SetAsString(MediaFormat::kMimeType, |
| 62 mime_type::kUncompressedVideo); |
| 63 media_format_.SetAsInteger(MediaFormat::kWidth, width_); |
| 64 media_format_.SetAsInteger(MediaFormat::kHeight, height_); |
| 65 |
| 66 decode_engine_->Initialize( |
| 67 message_loop(), |
| 68 av_stream, |
| 69 NewCallback(this, &FFmpegVideoDecoder::OnEmptyBufferDone), |
| 70 NewCallback(this, &FFmpegVideoDecoder::OnDecodeComplete), |
| 71 NewRunnableMethod(this, |
| 72 &FFmpegVideoDecoder::OnInitializeComplete, |
| 73 success, |
| 74 done_runner.release())); |
| 75 } |
| 76 |
| 77 void FFmpegVideoDecoder::OnInitializeComplete(bool* success, Task* done_cb) { |
| 78 AutoTaskRunner done_runner(done_cb); |
| 79 |
| 80 *success = decode_engine_->state() == VideoDecodeEngine::kNormal; |
| 81 } |
| 82 |
| 83 void FFmpegVideoDecoder::DoSeek(base::TimeDelta time, Task* done_cb) { |
| 84 // Everything in the presentation time queue is invalid, clear the queue. |
| 85 while (!pts_heap_.IsEmpty()) |
| 86 pts_heap_.Pop(); |
| 87 |
| 88 // We're back where we started. It should be completely safe to flush here |
| 89 // since DecoderBase uses |expecting_discontinuous_| to verify that the next |
| 90 // time DoDecode() is called we will have a discontinuous buffer. |
| 91 // |
| 92 // TODO(ajwong): Should we put a guard here to prevent leaving kError. |
| 93 state_ = kNormal; |
| 94 |
| 95 decode_engine_->Flush(done_cb); |
| 96 } |
| 97 |
| 98 void FFmpegVideoDecoder::DoDecode(Buffer* buffer) { |
| 99 // TODO(ajwong): This DoDecode() and OnDecodeComplete() set of functions is |
| 100 // too complicated to easily unittest. The test becomes fragile. Try to |
| 101 // find a way to reorganize into smaller units for testing. |
| 102 |
| 103 // During decode, because reads are issued asynchronously, it is possible to |
| 104 // receive multiple end of stream buffers since each read is acked. When the |
| 105 // first end of stream buffer is read, FFmpeg may still have frames queued |
| 106 // up in the decoder so we need to go through the decode loop until it stops |
| 107 // giving sensible data. After that, the decoder should output empty |
| 108 // frames. There are three states the decoder can be in: |
| 109 // |
| 110 // kNormal: This is the starting state. Buffers are decoded. Decode errors |
| 111 // are discarded. |
| 112 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2 |
| 113 // until no more data is returned to flush out remaining |
| 114 // frames. The input buffer is ignored at this point. |
| 115 // kDecodeFinished: All calls return empty frames. |
| 116 // |
| 117 // These are the possible state transitions. |
| 118 // |
| 119 // kNormal -> kFlushCodec: |
| 120 // When buffer->IsEndOfStream() is first true. |
| 121 // kNormal -> kDecodeFinished: |
| 122 // A catastrophic failure occurs, and decoding needs to stop. |
| 123 // kFlushCodec -> kDecodeFinished: |
| 124 // When avcodec_decode_video2() returns 0 data or errors out. |
| 125 // (any state) -> kNormal: |
| 126 // Any time buffer->IsDiscontinuous() is true. |
| 127 // |
| 128 // If the decoding is finished, we just always return empty frames. |
| 129 if (state_ == kDecodeFinished) { |
| 130 EnqueueEmptyFrame(); |
| 131 OnEmptyBufferDone(NULL); |
| 132 return; |
| 133 } |
| 134 |
| 135 // Transition to kFlushCodec on the first end of stream buffer. |
| 136 if (state_ == kNormal && buffer->IsEndOfStream()) { |
| 137 state_ = kFlushCodec; |
| 138 } |
| 139 |
| 140 // Push all incoming timestamps into the priority queue as long as we have |
| 141 // not yet received an end of stream buffer. It is important that this line |
| 142 // stay below the state transition into kFlushCodec done above. |
| 143 // |
| 144 // TODO(ajwong): This push logic, along with the pop logic below needs to |
| 145 // be reevaluated to correctly handle decode errors. |
| 146 if (state_ == kNormal && |
| 147 buffer->GetTimestamp() != StreamSample::kInvalidTimestamp) { |
| 148 pts_heap_.Push(buffer->GetTimestamp()); |
| 149 } |
| 150 |
| 151 // Otherwise, attempt to decode a single frame. |
| 152 decode_engine_->EmptyThisBuffer(buffer); |
| 153 } |
| 154 |
| 155 void FFmpegVideoDecoder::OnDecodeComplete( |
| 156 scoped_refptr<VideoFrame> video_frame) { |
| 157 if (video_frame.get()) { |
| 158 // If we actually got data back, enqueue a frame. |
| 159 last_pts_ = FindPtsAndDuration(*time_base_, &pts_heap_, last_pts_, |
| 160 video_frame.get()); |
| 161 |
| 162 video_frame->SetTimestamp(last_pts_.timestamp); |
| 163 video_frame->SetDuration(last_pts_.duration); |
| 164 EnqueueVideoFrame(video_frame); |
| 165 } else { |
| 166 // When in kFlushCodec, any errored decode, or a 0-lengthed frame, |
| 167 // is taken as a signal to stop decoding. |
| 168 if (state_ == kFlushCodec) { |
| 169 state_ = kDecodeFinished; |
| 170 EnqueueEmptyFrame(); |
| 171 } |
| 172 } |
| 173 |
| 174 OnEmptyBufferDone(NULL); |
| 175 } |
| 176 |
| 177 void FFmpegVideoDecoder::OnEmptyBufferDone(scoped_refptr<Buffer> buffer) { |
| 178 // Currently we just ignore the returned buffer. |
| 179 DecoderBase<VideoDecoder, VideoFrame>::OnDecodeComplete(); |
| 180 } |
| 181 |
| 182 void FFmpegVideoDecoder::EnqueueVideoFrame( |
| 183 const scoped_refptr<VideoFrame>& video_frame) { |
| 184 EnqueueResult(video_frame); |
| 185 } |
| 186 |
| 187 void FFmpegVideoDecoder::EnqueueEmptyFrame() { |
| 188 scoped_refptr<VideoFrame> video_frame; |
| 189 VideoFrame::CreateEmptyFrame(&video_frame); |
| 190 EnqueueResult(video_frame); |
| 191 } |
| 192 |
| 193 FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration( |
| 194 const AVRational& time_base, |
| 195 PtsHeap* pts_heap, |
| 196 const TimeTuple& last_pts, |
| 197 const VideoFrame* frame) { |
| 198 TimeTuple pts; |
| 199 |
| 200 // First search the VideoFrame for the pts. This is the most authoritative. |
| 201 // Make a special exclusion for the value pts == 0. Though this is |
| 202 // technically a valid value, it seems a number of FFmpeg codecs will |
| 203 // mistakenly always set pts to 0. |
| 204 // |
| 205 // TODO(scherkus): FFmpegVideoDecodeEngine should be able to detect this |
| 206 // situation and set the timestamp to kInvalidTimestamp. |
| 207 DCHECK(frame); |
| 208 base::TimeDelta timestamp = frame->GetTimestamp(); |
| 209 if (timestamp != StreamSample::kInvalidTimestamp && |
| 210 timestamp.ToInternalValue() != 0) { |
| 211 pts.timestamp = timestamp; |
| 212 } else if (!pts_heap->IsEmpty()) { |
| 213 // If the frame did not have pts, try to get the pts from the |pts_heap|. |
| 214 pts.timestamp = pts_heap->Top(); |
| 215 pts_heap->Pop(); |
| 216 } else if (last_pts.timestamp != StreamSample::kInvalidTimestamp && |
| 217 last_pts.duration != StreamSample::kInvalidTimestamp) { |
| 218 // Guess assuming this frame was the same as the last frame. |
| 219 pts.timestamp = last_pts.timestamp + last_pts.duration; |
| 220 } else { |
| 221 // Now we really have no clue!!! Mark an invalid timestamp and let the |
| 222 // video renderer handle it (i.e., drop frame). |
| 223 pts.timestamp = StreamSample::kInvalidTimestamp; |
| 224 } |
| 225 |
| 226 // Fill in the duration, using the frame itself as the authoratative source. |
| 227 base::TimeDelta duration = frame->GetDuration(); |
| 228 if (duration != StreamSample::kInvalidTimestamp && |
| 229 duration.ToInternalValue() != 0) { |
| 230 pts.duration = duration; |
| 231 } else { |
| 232 // Otherwise assume a normal frame duration. |
| 233 pts.duration = ConvertTimestamp(time_base, 1); |
| 234 } |
| 235 |
| 236 return pts; |
| 237 } |
| 238 |
| 239 void FFmpegVideoDecoder::SignalPipelineError() { |
| 240 host()->SetError(PIPELINE_ERROR_DECODE); |
| 241 state_ = kDecodeFinished; |
| 242 } |
| 243 |
| 244 void FFmpegVideoDecoder::SetVideoDecodeEngineForTest( |
| 245 VideoDecodeEngine* engine) { |
| 246 decode_engine_.reset(engine); |
| 247 } |
| 248 |
| 20 // static | 249 // static |
| 21 FilterFactory* FFmpegVideoDecoder::CreateFactory() { | 250 FilterFactory* FFmpegVideoDecoder::CreateFactory() { |
| 22 return new FilterFactoryImpl1<FFmpegVideoDecoder, FFmpegVideoDecodeEngine*>( | 251 return new FilterFactoryImpl1<FFmpegVideoDecoder, FFmpegVideoDecodeEngine*>( |
| 23 new FFmpegVideoDecodeEngine()); | 252 new FFmpegVideoDecodeEngine()); |
| 24 } | 253 } |
| 25 | 254 |
| 26 // static | 255 // static |
| 27 bool FFmpegVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) { | 256 bool FFmpegVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) { |
| 28 std::string mime_type; | 257 std::string mime_type; |
| 29 return format.GetAsString(MediaFormat::kMimeType, &mime_type) && | 258 return format.GetAsString(MediaFormat::kMimeType, &mime_type) && |
| 30 mime_type::kFFmpegVideo == mime_type; | 259 mime_type::kFFmpegVideo == mime_type; |
| 31 } | 260 } |
| 32 | 261 |
| 33 } // namespace media | 262 } // namespace media |
| OLD | NEW |