| 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/video_decoder_impl.h" | 5 #include "media/filters/video_decoder_impl.h" |
| 6 | 6 |
| 7 #include "base/task.h" | 7 #include "base/task.h" |
| 8 #include "media/base/filters.h" | 8 #include "media/base/filters.h" |
| 9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
| 10 #include "media/base/video_frame.h" | 10 #include "media/base/video_frame.h" |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 // not yet received an end of stream buffer. It is important that this line | 132 // not yet received an end of stream buffer. It is important that this line |
| 133 // stay below the state transition into kFlushCodec done above. | 133 // stay below the state transition into kFlushCodec done above. |
| 134 // | 134 // |
| 135 // TODO(ajwong): This push logic, along with the pop logic below needs to | 135 // TODO(ajwong): This push logic, along with the pop logic below needs to |
| 136 // be reevaluated to correctly handle decode errors. | 136 // be reevaluated to correctly handle decode errors. |
| 137 if (state_ == kNormal) { | 137 if (state_ == kNormal) { |
| 138 pts_heap_.Push(buffer->GetTimestamp()); | 138 pts_heap_.Push(buffer->GetTimestamp()); |
| 139 } | 139 } |
| 140 | 140 |
| 141 // Otherwise, attempt to decode a single frame. | 141 // Otherwise, attempt to decode a single frame. |
| 142 AVFrame* yuv_frame = avcodec_alloc_frame(); | |
| 143 bool* got_frame = new bool; | 142 bool* got_frame = new bool; |
| 143 scoped_refptr<VideoFrame>* video_frame = new scoped_refptr<VideoFrame>(NULL); |
| 144 decode_engine_->DecodeFrame( | 144 decode_engine_->DecodeFrame( |
| 145 buffer, | 145 buffer, |
| 146 yuv_frame, | 146 video_frame, |
| 147 got_frame, | 147 got_frame, |
| 148 NewRunnableMethod(this, | 148 NewRunnableMethod(this, |
| 149 &VideoDecoderImpl::OnDecodeComplete, | 149 &VideoDecoderImpl::OnDecodeComplete, |
| 150 yuv_frame, | 150 video_frame, |
| 151 got_frame, | 151 got_frame, |
| 152 done_runner.release())); | 152 done_runner.release())); |
| 153 } | 153 } |
| 154 | 154 |
| 155 void VideoDecoderImpl::OnDecodeComplete(AVFrame* yuv_frame, bool* got_frame, | 155 void VideoDecoderImpl::OnDecodeComplete(scoped_refptr<VideoFrame>* video_frame, |
| 156 Task* done_cb) { | 156 bool* got_frame, Task* done_cb) { |
| 157 // Note: The |done_runner| must be declared *last* to ensure proper | 157 // Note: The |done_runner| must be declared *last* to ensure proper |
| 158 // destruction order. | 158 // destruction order. |
| 159 scoped_ptr_malloc<AVFrame, ScopedPtrAVFree> yuv_frame_deleter(yuv_frame); | |
| 160 scoped_ptr<bool> got_frame_deleter(got_frame); | 159 scoped_ptr<bool> got_frame_deleter(got_frame); |
| 160 scoped_ptr<scoped_refptr<VideoFrame> > video_frame_deleter(video_frame); |
| 161 AutoTaskRunner done_runner(done_cb); | 161 AutoTaskRunner done_runner(done_cb); |
| 162 | 162 |
| 163 // If we actually got data back, enqueue a frame. | 163 // If we actually got data back, enqueue a frame. |
| 164 if (*got_frame) { | 164 if (*got_frame) { |
| 165 last_pts_ = FindPtsAndDuration(*time_base_, pts_heap_, last_pts_, | 165 last_pts_ = FindPtsAndDuration(*time_base_, pts_heap_, last_pts_, |
| 166 yuv_frame); | 166 video_frame->get()); |
| 167 | 167 |
| 168 // Pop off a pts on a successful decode since we are "using up" one | 168 // Pop off a pts on a successful decode since we are "using up" one |
| 169 // timestamp. | 169 // timestamp. |
| 170 // | 170 // |
| 171 // TODO(ajwong): Do we need to pop off a pts when avcodec_decode_video2() | 171 // TODO(ajwong): Do we need to pop off a pts when avcodec_decode_video2() |
| 172 // returns < 0? The rationale is that when get_picture_ptr == 0, we skip | 172 // returns < 0? The rationale is that when get_picture_ptr == 0, we skip |
| 173 // popping a pts because no frame was produced. However, when | 173 // popping a pts because no frame was produced. However, when |
| 174 // avcodec_decode_video2() returns false, it is a decode error, which | 174 // avcodec_decode_video2() returns false, it is a decode error, which |
| 175 // if it means a frame is dropped, may require us to pop one more time. | 175 // if it means a frame is dropped, may require us to pop one more time. |
| 176 if (!pts_heap_.IsEmpty()) { | 176 if (!pts_heap_.IsEmpty()) { |
| 177 pts_heap_.Pop(); | 177 pts_heap_.Pop(); |
| 178 } else { | 178 } else { |
| 179 NOTREACHED() << "Attempting to decode more frames than were input."; | 179 NOTREACHED() << "Attempting to decode more frames than were input."; |
| 180 } | 180 } |
| 181 | 181 |
| 182 if (!EnqueueVideoFrame( | 182 (*video_frame)->SetTimestamp(last_pts_.timestamp); |
| 183 decode_engine_->GetSurfaceFormat(), last_pts_, yuv_frame)) { | 183 (*video_frame)->SetDuration(last_pts_.duration); |
| 184 // On an EnqueueEmptyFrame error, error out the whole pipeline and | 184 EnqueueVideoFrame(*video_frame); |
| 185 // set the state to kDecodeFinished. | |
| 186 SignalPipelineError(); | |
| 187 } | |
| 188 } else { | 185 } else { |
| 189 // When in kFlushCodec, any errored decode, or a 0-lengthed frame, | 186 // When in kFlushCodec, any errored decode, or a 0-lengthed frame, |
| 190 // is taken as a signal to stop decoding. | 187 // is taken as a signal to stop decoding. |
| 191 if (state_ == kFlushCodec) { | 188 if (state_ == kFlushCodec) { |
| 192 state_ = kDecodeFinished; | 189 state_ = kDecodeFinished; |
| 193 EnqueueEmptyFrame(); | 190 EnqueueEmptyFrame(); |
| 194 } | 191 } |
| 195 } | 192 } |
| 196 } | 193 } |
| 197 | 194 |
| 198 bool VideoDecoderImpl::EnqueueVideoFrame(VideoFrame::Format surface_format, | 195 void VideoDecoderImpl::EnqueueVideoFrame( |
| 199 const TimeTuple& time, | 196 const scoped_refptr<VideoFrame>& video_frame) { |
| 200 const AVFrame* frame) { | |
| 201 // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675 | |
| 202 // The decoder is in a bad state and not decoding correctly. | |
| 203 // Checking for NULL avoids a crash in CopyPlane(). | |
| 204 if (!frame->data[VideoFrame::kYPlane] || | |
| 205 !frame->data[VideoFrame::kUPlane] || | |
| 206 !frame->data[VideoFrame::kVPlane]) { | |
| 207 return true; | |
| 208 } | |
| 209 | |
| 210 scoped_refptr<VideoFrame> video_frame; | |
| 211 VideoFrame::CreateFrame(surface_format, width_, height_, | |
| 212 time.timestamp, time.duration, &video_frame); | |
| 213 if (!video_frame) { | |
| 214 return false; | |
| 215 } | |
| 216 | |
| 217 // Copy the frame data since FFmpeg reuses internal buffers for AVFrame | |
| 218 // output, meaning the data is only valid until the next | |
| 219 // avcodec_decode_video() call. | |
| 220 // TODO(scherkus): figure out pre-allocation/buffer cycling scheme. | |
| 221 // TODO(scherkus): is there a cleaner way to figure out the # of planes? | |
| 222 CopyPlane(VideoFrame::kYPlane, *video_frame, frame); | |
| 223 CopyPlane(VideoFrame::kUPlane, *video_frame, frame); | |
| 224 CopyPlane(VideoFrame::kVPlane, *video_frame, frame); | |
| 225 EnqueueResult(video_frame); | 197 EnqueueResult(video_frame); |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 void VideoDecoderImpl::CopyPlane(size_t plane, | |
| 230 const VideoFrame& video_frame, | |
| 231 const AVFrame* frame) { | |
| 232 DCHECK(video_frame.width() % 2 == 0); | |
| 233 const uint8* source = frame->data[plane]; | |
| 234 const size_t source_stride = frame->linesize[plane]; | |
| 235 uint8* dest = video_frame.data(plane); | |
| 236 const size_t dest_stride = video_frame.stride(plane); | |
| 237 size_t bytes_per_line = video_frame.width(); | |
| 238 size_t copy_lines = video_frame.height(); | |
| 239 if (plane != VideoFrame::kYPlane) { | |
| 240 bytes_per_line /= 2; | |
| 241 if (video_frame.format() == VideoFrame::YV12) { | |
| 242 copy_lines = (copy_lines + 1) / 2; | |
| 243 } | |
| 244 } | |
| 245 DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride); | |
| 246 for (size_t i = 0; i < copy_lines; ++i) { | |
| 247 memcpy(dest, source, bytes_per_line); | |
| 248 source += source_stride; | |
| 249 dest += dest_stride; | |
| 250 } | |
| 251 } | 198 } |
| 252 | 199 |
| 253 void VideoDecoderImpl::EnqueueEmptyFrame() { | 200 void VideoDecoderImpl::EnqueueEmptyFrame() { |
| 254 scoped_refptr<VideoFrame> video_frame; | 201 scoped_refptr<VideoFrame> video_frame; |
| 255 VideoFrame::CreateEmptyFrame(&video_frame); | 202 VideoFrame::CreateEmptyFrame(&video_frame); |
| 256 EnqueueResult(video_frame); | 203 EnqueueResult(video_frame); |
| 257 } | 204 } |
| 258 | 205 |
| 259 VideoDecoderImpl::TimeTuple VideoDecoderImpl::FindPtsAndDuration( | 206 VideoDecoderImpl::TimeTuple VideoDecoderImpl::FindPtsAndDuration( |
| 260 const AVRational& time_base, | 207 const AVRational& time_base, |
| 261 const PtsHeap& pts_heap, | 208 const PtsHeap& pts_heap, |
| 262 const TimeTuple& last_pts, | 209 const TimeTuple& last_pts, |
| 263 const AVFrame* frame) { | 210 const VideoFrame* frame) { |
| 264 TimeTuple pts; | 211 TimeTuple pts; |
| 265 | 212 |
| 266 // Default |repeat_pict| to 0 because if there is no frame information, | 213 // First search the VideoFrame for the pts. This is the most authoritative. |
| 267 // we just assume the frame only plays for one time_base. | 214 // Make a special exclusion for the value pts == 0. Though this is |
| 268 int repeat_pict = 0; | 215 // technically a valid value, it seems a number of ffmpeg codecs will |
| 216 // mistakenly always set pts to 0. |
| 217 DCHECK(frame); |
| 218 base::TimeDelta timestamp = frame->GetTimestamp(); |
| 219 if (timestamp != StreamSample::kInvalidTimestamp && |
| 220 timestamp.ToInternalValue() != 0) { |
| 221 pts.timestamp = ConvertTimestamp(time_base, timestamp.ToInternalValue()); |
| 222 pts.duration = ConvertTimestamp(time_base, 1 + frame->GetRepeatCount()); |
| 223 return pts; |
| 224 } |
| 269 | 225 |
| 270 // First search the AVFrame for the pts. This is the most authoritative. | 226 if (!pts_heap.IsEmpty()) { |
| 271 // Make a special exclusion for the value frame->pts == 0. Though this | 227 // If the frame did not have pts, try to get the pts from the |pts_heap|. |
| 272 // is technically a valid value, it seems a number of ffmpeg codecs will | |
| 273 // mistakenly always set frame->pts to 0. | |
| 274 // | |
| 275 // Oh, and we have to cast AV_NOPTS_VALUE since it ends up becoming unsigned | |
| 276 // because the value they use doesn't fit in a signed 64-bit number which | |
| 277 // produces a signedness comparison warning on gcc. | |
| 278 if (frame && | |
| 279 (frame->pts != static_cast<int64_t>(AV_NOPTS_VALUE)) && | |
| 280 (frame->pts != 0)) { | |
| 281 pts.timestamp = ConvertTimestamp(time_base, frame->pts); | |
| 282 repeat_pict = frame->repeat_pict; | |
| 283 } else if (!pts_heap.IsEmpty()) { | |
| 284 // If the frame did not have pts, try to get the pts from the | |
| 285 // |pts_heap|. | |
| 286 pts.timestamp = pts_heap.Top(); | 228 pts.timestamp = pts_heap.Top(); |
| 287 } else { | 229 } else { |
| 288 DCHECK(last_pts.timestamp != StreamSample::kInvalidTimestamp); | 230 DCHECK(last_pts.timestamp != StreamSample::kInvalidTimestamp); |
| 289 DCHECK(last_pts.duration != StreamSample::kInvalidTimestamp); | 231 DCHECK(last_pts.duration != StreamSample::kInvalidTimestamp); |
| 290 // Unable to read the pts from anywhere. Time to guess. | 232 // Unable to read the pts from anywhere. Time to guess. |
| 291 pts.timestamp = last_pts.timestamp + last_pts.duration; | 233 pts.timestamp = last_pts.timestamp + last_pts.duration; |
| 292 } | 234 } |
| 293 | 235 |
| 294 // Fill in the duration while accounting for repeated frames. | 236 // Fill in the duration while accounting for repeated frames. |
| 295 // | 237 pts.duration = ConvertTimestamp(time_base, 1); |
| 296 // TODO(ajwong): Make sure this formula is correct. | |
| 297 pts.duration = ConvertTimestamp(time_base, 1 + repeat_pict); | |
| 298 | 238 |
| 299 return pts; | 239 return pts; |
| 300 } | 240 } |
| 301 | 241 |
| 302 void VideoDecoderImpl::SignalPipelineError() { | 242 void VideoDecoderImpl::SignalPipelineError() { |
| 303 host()->SetError(PIPELINE_ERROR_DECODE); | 243 host()->SetError(PIPELINE_ERROR_DECODE); |
| 304 state_ = kDecodeFinished; | 244 state_ = kDecodeFinished; |
| 305 } | 245 } |
| 306 | 246 |
| 307 void VideoDecoderImpl::SetVideoDecodeEngineForTest( | 247 void VideoDecoderImpl::SetVideoDecodeEngineForTest( |
| 308 VideoDecodeEngine* engine) { | 248 VideoDecodeEngine* engine) { |
| 309 decode_engine_.reset(engine); | 249 decode_engine_.reset(engine); |
| 310 } | 250 } |
| 311 | 251 |
| 312 } // namespace media | 252 } // namespace media |
| OLD | NEW |