blob: 5bd242e0f214cb268dcf29b82e8afea9331caeb4 [file] [log] [blame]
// Copyright (c) 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_CODEC_BRIDGE_H_
#define MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_
#include <jni.h>
#include <string>
#include "base/android/scoped_java_ref.h"
#include "base/time/time.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/video_decoder_config.h"
#include "ui/gfx/size.h"
namespace media {
struct SubsampleEntry;
// This class serves as a bridge for native code to call java functions inside
// Android MediaCodec class. For more information on Android MediaCodec, check
// http://developer.android.com/reference/android/media/MediaCodec.html
// Note: MediaCodec is only available on JB and greater.
// Use AudioCodecBridge or VideoCodecBridge to create an instance of this
// object.
class MEDIA_EXPORT MediaCodecBridge {
public:
enum DequeueBufferInfo {
INFO_OUTPUT_BUFFERS_CHANGED = -3,
INFO_OUTPUT_FORMAT_CHANGED = -2,
INFO_TRY_AGAIN_LATER = -1,
INFO_MEDIA_CODEC_ERROR = -1000,
};
static const base::TimeDelta kTimeOutInfinity;
static const base::TimeDelta kTimeOutNoWait;
// Returns true if MediaCodec is available on the device.
static bool IsAvailable();
virtual ~MediaCodecBridge();
// Resets both input and output, all indices previously returned in calls to
// DequeueInputBuffer() and DequeueOutputBuffer() become invalid.
// Please note that this clears all the inputs in the media codec. In other
// words, there will be no outputs until new input is provided.
void Reset();
// Finishes the decode/encode session. The instance remains active
// and ready to be StartAudio/Video()ed again. HOWEVER, due to the buggy
// vendor's implementation , b/8125974, Stop() -> StartAudio/Video() may not
// work on some devices. For reliability, Stop() -> delete and recreate new
// instance -> StartAudio/Video() is recommended.
void Stop();
// Used for getting output format. This is valid after DequeueInputBuffer()
// returns a format change by returning INFO_OUTPUT_FORMAT_CHANGED
void GetOutputFormat(int* width, int* height);
// Submits a byte array to the given input buffer. Call this after getting an
// available buffer from DequeueInputBuffer(). Returns the number of bytes
// put to the input buffer.
size_t QueueInputBuffer(int index, const uint8* data, int size,
const base::TimeDelta& presentation_time);
// Similar to the above call, but submits a buffer that is encrypted.
size_t QueueSecureInputBuffer(
int index, const uint8* data, int data_size,
const uint8* key_id, int key_id_size,
const uint8* iv, int iv_size,
const SubsampleEntry* subsamples, int subsamples_size,
const base::TimeDelta& presentation_time);
// Submits an empty buffer with a EOS (END OF STREAM) flag.
void QueueEOS(int input_buffer_index);
// Returns an index (>=0) of an input buffer to be filled with valid data,
// INFO_TRY_AGAIN_LATER if no such buffer is currently available, or
// INFO_MEDIA_CODEC_ERROR if unexpected error happens.
// Use kTimeOutInfinity for infinite timeout.
int DequeueInputBuffer(base::TimeDelta timeout);
// Dequeues an output buffer, block at most timeout_us microseconds.
// Returns the index of an output buffer that has been successfully decoded
// or one of DequeueBufferInfo above.
// Use kTimeOutInfinity for infinite timeout.
int DequeueOutputBuffer(
base::TimeDelta timeout, size_t* offset, size_t* size,
base::TimeDelta* presentation_time, bool* end_of_stream);
// Returns the buffer to the codec. If you previously specified a surface
// when configuring this video decoder you can optionally render the buffer.
void ReleaseOutputBuffer(int index, bool render);
// Gets output buffers from media codec and keeps them inside the java class.
// To access them, use DequeueOutputBuffer().
void GetOutputBuffers();
static bool RegisterMediaCodecBridge(JNIEnv* env);
protected:
explicit MediaCodecBridge(const char* mime);
// Calls start() against the media codec instance. Used in StartXXX() after
// configuring media codec.
void StartInternal();
jobject media_codec() { return j_media_codec_.obj(); }
private:
// Fills a particular input buffer and returns the size of copied data.
size_t FillInputBuffer(int index, const uint8* data, int data_size);
// Java MediaCodec instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_codec_;
DISALLOW_COPY_AND_ASSIGN(MediaCodecBridge);
};
class AudioCodecBridge : public MediaCodecBridge {
public:
// Returns an AudioCodecBridge instance if |codec| is supported, or a NULL
// pointer otherwise.
static AudioCodecBridge* Create(const AudioCodec codec);
// Start the audio codec bridge.
bool Start(const AudioCodec codec, int sample_rate, int channel_count,
const uint8* extra_data, size_t extra_data_size,
bool play_audio, jobject media_crypto);
// Play the output buffer. This call must be called after
// DequeueOutputBuffer() and before ReleaseOutputBuffer.
void PlayOutputBuffer(int index, size_t size);
private:
explicit AudioCodecBridge(const char* mime);
// Configure the java MediaFormat object with the extra codec data passed in.
bool ConfigureMediaFormat(jobject j_format, const AudioCodec codec,
const uint8* extra_data, size_t extra_data_size);
};
class MEDIA_EXPORT VideoCodecBridge : public MediaCodecBridge {
public:
// Returns an VideoCodecBridge instance if |codec| is supported, or a NULL
// pointer otherwise.
static VideoCodecBridge* Create(const VideoCodec codec);
// Start the video codec bridge.
// TODO(qinmin): Pass codec specific data if available.
bool Start(const VideoCodec codec, const gfx::Size& size, jobject surface,
jobject media_crypto);
private:
explicit VideoCodecBridge(const char* mime);
};
} // namespace media
#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_BRIDGE_H_