blob: b91b0150a0f4c368116c69cc41b830f724cf368a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_FILTERS_GPU_VIDEO_DECODER_H_
#define MEDIA_FILTERS_GPU_VIDEO_DECODER_H_
#include <deque>
#include <list>
#include <map>
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder.h"
#include "media/video/video_decode_accelerator.h"
class MessageLoop;
template <class T> class scoped_refptr;
namespace base {
class MessageLoopProxy;
class SharedMemory;
}
namespace media {
// GPU-accelerated video decoder implementation. Relies on
// AcceleratedVideoDecoderMsg_Decode and friends.
// All methods internally trampoline to the |message_loop| passed to the ctor.
class MEDIA_EXPORT GpuVideoDecoder
: public VideoDecoder,
public VideoDecodeAccelerator::Client {
public:
// Helper interface for specifying factories needed to instantiate a
// GpuVideoDecoder.
class MEDIA_EXPORT Factories : public base::RefCountedThreadSafe<Factories> {
public:
// Caller owns returned pointer.
virtual VideoDecodeAccelerator* CreateVideoDecodeAccelerator(
VideoCodecProfile, VideoDecodeAccelerator::Client*) = 0;
// Allocate & delete native textures.
virtual bool CreateTextures(int32 count, const gfx::Size& size,
std::vector<uint32>* texture_ids,
uint32* texture_target) = 0;
virtual void DeleteTexture(uint32 texture_id) = 0;
// Allocate & return a shared memory segment. Caller is responsible for
// Close()ing the returned pointer.
virtual base::SharedMemory* CreateSharedMemory(size_t size) = 0;
protected:
friend class base::RefCountedThreadSafe<Factories>;
virtual ~Factories();
};
GpuVideoDecoder(MessageLoop* message_loop,
MessageLoop* vda_loop,
const scoped_refptr<Factories>& factories);
// VideoDecoder implementation.
virtual void Initialize(const scoped_refptr<DemuxerStream>& stream,
const PipelineStatusCB& status_cb,
const StatisticsCB& statistics_cb) OVERRIDE;
virtual void Read(const ReadCB& read_cb) OVERRIDE;
virtual void Reset(const base::Closure& closure) OVERRIDE;
virtual void Stop(const base::Closure& closure) OVERRIDE;
virtual const gfx::Size& natural_size() OVERRIDE;
virtual bool HasAlpha() const OVERRIDE;
virtual void PrepareForShutdownHack() OVERRIDE;
// VideoDecodeAccelerator::Client implementation.
virtual void NotifyInitializeDone() OVERRIDE;
virtual void ProvidePictureBuffers(uint32 count,
const gfx::Size& size) OVERRIDE;
virtual void DismissPictureBuffer(int32 id) OVERRIDE;
virtual void PictureReady(const media::Picture& picture) OVERRIDE;
virtual void NotifyEndOfBitstreamBuffer(int32 id) OVERRIDE;
virtual void NotifyFlushDone() OVERRIDE;
virtual void NotifyResetDone() OVERRIDE;
virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE;
protected:
virtual ~GpuVideoDecoder();
private:
enum State {
kNormal,
// Avoid the use of "flush" in these enums because the term is overloaded:
// Filter::Flush() means drop pending data on the floor, but
// VideoDecodeAccelerator::Flush() means drain pending data (Filter::Flush()
// actually corresponds to VideoDecodeAccelerator::Reset(), confusingly
// enough).
kDrainingDecoder,
kDecoderDrained,
};
// If no demuxer read is in flight and no bitstream buffers are in the
// decoder, kick some off demuxing/decoding.
void EnsureDemuxOrDecode();
// Callback to pass to demuxer_stream_->Read() for receiving encoded bits.
void RequestBufferDecode(const scoped_refptr<Buffer>& buffer);
// Enqueue a frame for later delivery (or drop it on the floor if a
// vda->Reset() is in progress) and trigger out-of-line delivery of the oldest
// ready frame to the client if there is a pending read. A NULL |frame|
// merely triggers delivery, and requires the ready_video_frames_ queue not be
// empty.
void EnqueueFrameAndTriggerFrameDelivery(
const scoped_refptr<VideoFrame>& frame);
// Indicate the picturebuffer can be reused by the decoder.
void ReusePictureBuffer(int64 picture_buffer_id);
void RecordBufferTimeData(
const BitstreamBuffer& bitstream_buffer, const Buffer& buffer);
void GetBufferTimeData(
int32 id, base::TimeDelta* timestamp, base::TimeDelta* duration);
// A shared memory segment and its allocated size.
struct SHMBuffer {
SHMBuffer(base::SharedMemory* m, size_t s);
~SHMBuffer();
base::SharedMemory* shm;
size_t size;
};
// Request a shared-memory segment of at least |min_size| bytes. Will
// allocate as necessary. Caller does not own returned pointer.
SHMBuffer* GetSHM(size_t min_size);
// Return a shared-memory segment to the available pool.
void PutSHM(SHMBuffer* shm_buffer);
StatisticsCB statistics_cb_;
// TODO(scherkus): I think this should be calculated by VideoRenderers based
// on information provided by VideoDecoders (i.e., aspect ratio).
gfx::Size natural_size_;
// Frame duration specified in the video stream's configuration, or 0 if not
// present.
base::TimeDelta config_frame_duration_;
// Pointer to the demuxer stream that will feed us compressed buffers.
scoped_refptr<DemuxerStream> demuxer_stream_;
// MessageLoop on which to fire callbacks and trampoline calls to this class
// if they arrive on other loops.
scoped_refptr<base::MessageLoopProxy> gvd_loop_proxy_;
// Message loop on which to makes all calls to vda_. (beware this loop may be
// paused during the Pause/Flush/Stop dance PipelineImpl::Stop() goes
// through).
scoped_refptr<base::MessageLoopProxy> vda_loop_proxy_;
scoped_refptr<Factories> factories_;
// Populated during Initialize() (on success) and unchanged thereafter.
scoped_refptr<VideoDecodeAccelerator> vda_;
// Callbacks that are !is_null() only during their respective operation being
// asynchronously executed.
ReadCB pending_read_cb_;
base::Closure pending_reset_cb_;
State state_;
// Is a demuxer read in flight?
bool demuxer_read_in_progress_;
// Shared-memory buffer pool. Since allocating SHM segments requires a
// round-trip to the browser process, we keep allocation out of the
// steady-state of the decoder.
std::vector<SHMBuffer*> available_shm_segments_;
// Book-keeping variables.
struct BufferPair {
BufferPair(SHMBuffer* s, const scoped_refptr<Buffer>& b);
~BufferPair();
SHMBuffer* shm_buffer;
scoped_refptr<Buffer> buffer;
};
std::map<int32, BufferPair> bitstream_buffers_in_decoder_;
std::map<int32, PictureBuffer> picture_buffers_in_decoder_;
// The texture target used for decoded pictures.
uint32 decoder_texture_target_;
struct BufferTimeData {
BufferTimeData(int32 bbid, base::TimeDelta ts, base::TimeDelta dur);
~BufferTimeData();
int32 bitstream_buffer_id;
base::TimeDelta timestamp;
base::TimeDelta duration;
};
std::list<BufferTimeData> input_buffer_time_data_;
// picture_buffer_id and the frame wrapping the corresponding Picture, for
// frames that have been decoded but haven't been requested by a Read() yet.
std::list<scoped_refptr<VideoFrame> > ready_video_frames_;
int64 next_picture_buffer_id_;
int64 next_bitstream_buffer_id_;
// Indicates PrepareForShutdownHack()'s been called. Makes further calls to
// this class not require the render thread's loop to be processing.
bool shutting_down_;
// Indicates decoding error occurred.
bool error_occured_;
DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoder);
};
} // namespace media
#endif // MEDIA_FILTERS_GPU_VIDEO_DECODER_H_