blob: 6ee086dea039b9378792a8480482975ca1a469b8 [file] [log] [blame]
// Copyright 2013 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_BASE_ANDROID_MEDIA_DECODER_JOB_H_
#define MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "media/base/android/demuxer_stream_player_params.h"
#include "media/base/android/media_codec_bridge.h"
namespace base {
class MessageLoopProxy;
}
namespace media {
// Class for managing all the decoding tasks. Each decoding task will be posted
// onto the same thread. The thread will be stopped once Stop() is called.
class MediaDecoderJob {
public:
struct Deleter {
inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
};
// Callback when a decoder job finishes its work. Args: whether decode
// finished successfully, presentation time, audio output bytes.
// If the presentation time is equal to kNoTimestamp(), the decoder job
// skipped rendering of the decoded output and the callback target should
// update its clock to avoid introducing extra delays to the next frame.
typedef base::Callback<void(MediaCodecStatus, const base::TimeDelta&,
size_t)> DecoderCallback;
// Callback when a decoder job finishes releasing the output buffer.
// Args: audio output bytes, must be 0 for video.
typedef base::Callback<void(size_t)> ReleaseOutputCompletionCallback;
virtual ~MediaDecoderJob();
// Called by MediaSourcePlayer when more data for this object has arrived.
void OnDataReceived(const DemuxerData& data);
// Prefetch so we know the decoder job has data when we call Decode().
// |prefetch_cb| - Run when prefetching has completed.
void Prefetch(const base::Closure& prefetch_cb);
// Called by MediaSourcePlayer to decode some data.
// |callback| - Run when decode operation has completed.
//
// Returns true if the next decode was started and |callback| will be
// called when the decode operation is complete.
// Returns false if a config change is needed. |callback| is ignored
// and will not be called.
bool Decode(const base::TimeTicks& start_time_ticks,
const base::TimeDelta& start_presentation_timestamp,
const DecoderCallback& callback);
// Called to stop the last Decode() early.
// If the decoder is in the process of decoding the next frame, then
// this method will just allow the decode to complete as normal. If
// this object is waiting for a data request to complete, then this method
// will wait for the data to arrive and then call the |callback|
// passed to Decode() with a status of MEDIA_CODEC_STOPPED. This ensures that
// the |callback| passed to Decode() is always called and the status
// reflects whether data was actually decoded or the decode terminated early.
void StopDecode();
// Flush the decoder.
void Flush();
// Enter prerolling state. The job must not currently be decoding.
void BeginPrerolling(const base::TimeDelta& preroll_timestamp);
bool prerolling() const { return prerolling_; }
bool is_decoding() const { return !decode_cb_.is_null(); }
protected:
MediaDecoderJob(const scoped_refptr<base::MessageLoopProxy>& decoder_loop,
MediaCodecBridge* media_codec_bridge,
const base::Closure& request_data_cb);
// Release the output buffer at index |output_buffer_index| and render it if
// |render_output| is true. Upon completion, |callback| will be called.
virtual void ReleaseOutputBuffer(
int output_buffer_index,
size_t size,
bool render_output,
const ReleaseOutputCompletionCallback& callback) = 0;
// Returns true if the "time to render" needs to be computed for frames in
// this decoder job.
virtual bool ComputeTimeToRender() const = 0;
private:
// Causes this instance to be deleted on the thread it is bound to.
void Release();
MediaCodecStatus QueueInputBuffer(const AccessUnit& unit);
// Returns true if this object has data to decode.
bool HasData() const;
// Initiates a request for more data.
// |done_cb| is called when more data is available in |received_data_|.
void RequestData(const base::Closure& done_cb);
// Posts a task to start decoding the next access unit in |received_data_|.
void DecodeNextAccessUnit(
const base::TimeTicks& start_time_ticks,
const base::TimeDelta& start_presentation_timestamp);
// Helper function to decoder data on |thread_|. |unit| contains all the data
// to be decoded. |start_time_ticks| and |start_presentation_timestamp|
// represent the system time and the presentation timestamp when the first
// frame is rendered. We use these information to estimate when the current
// frame should be rendered. If |needs_flush| is true, codec needs to be
// flushed at the beginning of this call.
void DecodeInternal(const AccessUnit& unit,
const base::TimeTicks& start_time_ticks,
const base::TimeDelta& start_presentation_timestamp,
bool needs_flush,
const DecoderCallback& callback);
// Called on the UI thread to indicate that one decode cycle has completed.
// Completes any pending job destruction or any pending decode stop. If
// destruction was not pending, passes its arguments to |decode_cb_|.
void OnDecodeCompleted(MediaCodecStatus status,
const base::TimeDelta& presentation_timestamp,
size_t audio_output_bytes);
// The UI message loop where callbacks should be dispatched.
scoped_refptr<base::MessageLoopProxy> ui_loop_;
// The message loop that decoder job runs on.
scoped_refptr<base::MessageLoopProxy> decoder_loop_;
// The media codec bridge used for decoding. Owned by derived class.
// NOTE: This MUST NOT be accessed in the destructor.
MediaCodecBridge* media_codec_bridge_;
// Whether the decoder needs to be flushed.
bool needs_flush_;
// Whether input EOS is encountered.
// TODO(wolenetz/qinmin): Protect with a lock. See http://crbug.com/320043.
bool input_eos_encountered_;
// Whether output EOS is encountered.
bool output_eos_encountered_;
// Tracks whether DecodeInternal() should skip decoding if the first access
// unit is EOS or empty, and report |MEDIA_CODEC_OUTPUT_END_OF_STREAM|. This
// is to work around some decoders that could crash otherwise. See
// http://b/11696552.
bool skip_eos_enqueue_;
// The timestamp the decoder needs to preroll to. If an access unit's
// timestamp is smaller than |preroll_timestamp_|, don't render it.
// TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
// is not very accurate.
base::TimeDelta preroll_timestamp_;
// Indicates prerolling state. If true, this job has not yet decoded output
// that it will render, since the most recent of job construction or
// BeginPrerolling(). If false, |preroll_timestamp_| has been reached.
// TODO(qinmin): Comparing access unit's timestamp with |preroll_timestamp_|
// is not very accurate.
bool prerolling_;
// Weak pointer passed to media decoder jobs for callbacks. It is bounded to
// the decoder thread.
base::WeakPtrFactory<MediaDecoderJob> weak_this_;
// Callback used to request more data.
base::Closure request_data_cb_;
// Callback to run when new data has been received.
base::Closure on_data_received_cb_;
// Callback to run when the current Decode() operation completes.
DecoderCallback decode_cb_;
// The current access unit being processed.
size_t access_unit_index_;
// Data received over IPC from last RequestData() operation.
DemuxerData received_data_;
// The index of input buffer that can be used by QueueInputBuffer().
// If the index is uninitialized or invalid, it must be -1.
int input_buf_index_;
bool stop_decode_pending_;
// Indicates that this object should be destroyed once the current
// Decode() has completed. This gets set when Release() gets called
// while there is a decode in progress.
bool destroy_pending_;
DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDecoderJob);
};
} // namespace media
#endif // MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_