Initial implementation of BMediaEncoder

* People interested, please review!
* This is based on the patch from Fredrik Moden which was based on
the Oleg Krysenkov one.
* The original patch has been reworked by myself.
* Adapted the code to work with the new PluginManager API which
differently than before doesn't need to contact the media_server.
This commit is contained in:
Dario Casalinuovo
2015-12-02 16:08:06 +01:00
parent 0df4a177d7
commit 2b51499295
9 changed files with 339 additions and 61 deletions
+13 -2
View File
@@ -8,6 +8,15 @@
#include <MediaFormats.h> #include <MediaFormats.h>
namespace BPrivate {
namespace media {
class Encoder;
class EncoderPlugin;
}
}
using namespace BPrivate::media;
class BMediaEncoder { class BMediaEncoder {
public: public:
@@ -65,6 +74,8 @@ private:
BMediaEncoder& operator=(const BMediaEncoder& other); BMediaEncoder& operator=(const BMediaEncoder& other);
private: private:
status_t _AttachToEncoder();
static status_t write_chunk(void* classPtr, static status_t write_chunk(void* classPtr,
const void* buffer, size_t size, const void* buffer, size_t size,
media_encode_info* info); media_encode_info* info);
@@ -73,7 +84,7 @@ private:
void ReleaseEncoder(); void ReleaseEncoder();
uint32 _reserved_was_fEncoderMgr; uint32 _reserved_was_fEncoderMgr;
uint32 _reserved_was_fEncoder; Encoder* fEncoder;
int32 fEncoderID; int32 fEncoderID;
bool fFormatValid; bool fFormatValid;
@@ -84,7 +95,7 @@ private:
}; };
class BMediaBufferEncoder: public BMediaEncoder { class BMediaBufferEncoder : public BMediaEncoder {
public: public:
BMediaBufferEncoder(); BMediaBufferEncoder();
BMediaBufferEncoder( BMediaBufferEncoder(
+4 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009, Haiku Inc. All rights reserved. * Copyright 2009-2015, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
*/ */
#ifndef _ENCODER_PLUGIN_H #ifndef _ENCODER_PLUGIN_H
@@ -122,6 +122,9 @@ public:
virtual Encoder* NewEncoder( virtual Encoder* NewEncoder(
const media_codec_info& codecInfo) = 0; const media_codec_info& codecInfo) = 0;
virtual Encoder* NewEncoder(
const media_format& format) = 0;
virtual status_t RegisterNextEncoder(int32* cookie, virtual status_t RegisterNextEncoder(int32* cookie,
media_codec_info* codecInfo, media_codec_info* codecInfo,
media_format_family* formatFamily, media_format_family* formatFamily,
+8 -2
View File
@@ -1,6 +1,8 @@
/* /*
* Copyright 2015, Dario Casalinuovo. All rights reserved.
* Copyright 2012, Fredrik Modéen. All rights reserved.
* Copyright 2004-2007, Marcus Overhagen. All rights reserved. * Copyright 2004-2007, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _PLUGIN_MANAGER_H #ifndef _PLUGIN_MANAGER_H
#define _PLUGIN_MANAGER_H #define _PLUGIN_MANAGER_H
@@ -51,6 +53,10 @@ public:
status_t CreateEncoder(Encoder** encoder, status_t CreateEncoder(Encoder** encoder,
const media_codec_info* codecInfo, const media_codec_info* codecInfo,
uint32 flags); uint32 flags);
status_t CreateEncoder(Encoder** encoder,
const media_format& format);
void DestroyEncoder(Encoder* encoder); void DestroyEncoder(Encoder* encoder);
private: private:
@@ -45,16 +45,38 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID, int bitRateScale)
fOwnContext(avcodec_alloc_context3(NULL)), fOwnContext(avcodec_alloc_context3(NULL)),
fContext(fOwnContext), fContext(fOwnContext),
fCodecInitStatus(CODEC_INIT_NEEDED), fCodecInitStatus(CODEC_INIT_NEEDED),
fFrame(avcodec_alloc_frame()), fFrame(avcodec_alloc_frame()),
fSwsContext(NULL), fSwsContext(NULL),
fFramesWritten(0)
fFramesWritten(0),
fChunkBuffer(new(std::nothrow) uint8[kDefaultChunkBufferSize])
{ {
TRACE("AVCodecEncoder::AVCodecEncoder()\n"); TRACE("AVCodecEncoder::AVCodecEncoder()\n");
_Init();
}
AVCodecEncoder::AVCodecEncoder(const media_format& format)
:
Encoder(),
fBitRateScale(1), // TODO: is it OK?
fCodecID(CodecID(-1)),
fCodec(NULL),
fOwnContext(avcodec_alloc_context3(NULL)),
fContext(fOwnContext),
fCodecInitStatus(CODEC_INIT_NEEDED),
fFrame(avcodec_alloc_frame()),
fSwsContext(NULL),
fFramesWritten(0)
{
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
_Init();
SetUp(&format);
}
void
AVCodecEncoder::_Init()
{
fChunkBuffer = new(std::nothrow) uint8[kDefaultChunkBufferSize];
if (fCodecID > 0) { if (fCodecID > 0) {
fCodec = avcodec_find_encoder(fCodecID); fCodec = avcodec_find_encoder(fCodecID);
TRACE(" found AVCodec for %u: %p\n", fCodecID, fCodec); TRACE(" found AVCodec for %u: %p\n", fCodecID, fCodec);
@@ -27,6 +27,8 @@ public:
AVCodecEncoder(uint32 codecID, AVCodecEncoder(uint32 codecID,
int bitRateScale); int bitRateScale);
AVCodecEncoder(const media_format& format);
virtual ~AVCodecEncoder(); virtual ~AVCodecEncoder();
virtual status_t AcceptedFormat( virtual status_t AcceptedFormat(
@@ -48,6 +50,7 @@ public:
// codec buffer size. // codec buffer size.
private: private:
void _Init();
status_t _Setup(); status_t _Setup();
bool _OpenCodecIfNeeded(); bool _OpenCodecIfNeeded();
@@ -156,6 +156,13 @@ FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo)
} }
Encoder*
FFmpegPlugin::NewEncoder(const media_format& format)
{
return new(std::nothrow)AVCodecEncoder(format);
}
status_t status_t
FFmpegPlugin::RegisterNextEncoder(int32* cookie, media_codec_info* _codecInfo, FFmpegPlugin::RegisterNextEncoder(int32* cookie, media_codec_info* _codecInfo,
media_format_family* _formatFamily, media_format* _inputFormat, media_format_family* _formatFamily, media_format* _inputFormat,
@@ -34,6 +34,9 @@ public:
virtual Encoder* NewEncoder( virtual Encoder* NewEncoder(
const media_codec_info& codecInfo); const media_codec_info& codecInfo);
virtual Encoder* NewEncoder(const media_format& format);
virtual status_t RegisterNextEncoder(int32* cookie, virtual status_t RegisterNextEncoder(int32* cookie,
media_codec_info* codecInfo, media_codec_info* codecInfo,
media_format_family* formatFamily, media_format_family* formatFamily,
+195 -48
View File
@@ -1,96 +1,185 @@
/*********************************************************************** /*
* AUTHOR: Marcus Overhagen * Copyright 2015, Dario Casalinuovo
* FILE: MediaEncoder.cpp * Copyright 2010, Oleg Krysenkov, beos344@mail.ru.
* DESCR: * Copyright 2012, Fredrik Modéen, [firstname]@[lastname].se.
***********************************************************************/ * Copyright 2004-2007, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <MediaEncoder.h> #include <MediaEncoder.h>
#include <EncoderPlugin.h>
#include <PluginManager.h>
#include <new>
#include "debug.h" #include "debug.h"
//TODO: SetTo, SetFormat, Enode Class
/************************************************************* /*************************************************************
* public BMediaEncoder * public BMediaEncoder
*************************************************************/ *************************************************************/
BMediaEncoder::BMediaEncoder() BMediaEncoder::BMediaEncoder()
:
fEncoder(NULL),
fInitStatus(B_NO_INIT)
{ {
UNIMPLEMENTED(); CALLED();
} }
BMediaEncoder::BMediaEncoder(const media_format *output_format) BMediaEncoder::BMediaEncoder(const media_format *output_format)
:
fEncoder(NULL),
fInitStatus(B_NO_INIT)
{ {
UNIMPLEMENTED(); CALLED();
SetTo(output_format);
} }
BMediaEncoder::BMediaEncoder(const media_codec_info *mci) BMediaEncoder::BMediaEncoder(const media_codec_info *mci)
:
fEncoder(NULL),
fInitStatus(B_NO_INIT)
{ {
UNIMPLEMENTED(); CALLED();
SetTo(mci);
} }
/* virtual */ /* virtual */
BMediaEncoder::~BMediaEncoder() BMediaEncoder::~BMediaEncoder()
{ {
UNIMPLEMENTED(); CALLED();
gPluginManager.DestroyEncoder(fEncoder);
fEncoder = NULL;
} }
status_t status_t
BMediaEncoder::InitCheck() const BMediaEncoder::InitCheck() const
{ {
UNIMPLEMENTED(); return fInitStatus;
return B_OK;
} }
status_t status_t
BMediaEncoder::SetTo(const media_format *output_format) BMediaEncoder::SetTo(const media_format *output_format)
{ {
UNIMPLEMENTED(); CALLED();
return B_OK;
gPluginManager.DestroyEncoder(fEncoder);
fEncoder = NULL;
fInitStatus = B_OK;
status_t err = B_ERROR;
if (output_format != NULL) {
media_format format = *output_format;
status_t err = gPluginManager.CreateEncoder(&fEncoder, format);
if (err != B_OK)
goto fail;
err = _AttachToEncoder();
if (err != B_OK)
goto fail;
err = SetFormat(NULL, &format);
if (err != B_OK)
goto fail;
return B_OK;
}
fail:
fInitStatus = err;
gPluginManager.DestroyEncoder(fEncoder);
fEncoder = NULL;
fInitStatus = B_NO_INIT;
return err;
} }
status_t status_t
BMediaEncoder::SetTo(const media_codec_info *mci) BMediaEncoder::SetTo(const media_codec_info *mci)
{ {
UNIMPLEMENTED(); CALLED();
gPluginManager.DestroyEncoder(fEncoder);
fEncoder = NULL;
status_t err = gPluginManager.CreateEncoder(&fEncoder, mci, 0);
if (err < B_OK)
goto fail;
err = _AttachToEncoder();
if (err < B_OK)
goto fail;
fInitStatus = B_OK;
return B_OK; return B_OK;
fail:
gPluginManager.DestroyEncoder(fEncoder);
fEncoder = NULL;
fInitStatus = B_NO_INIT;
return err;
} }
status_t status_t
BMediaEncoder::SetFormat(media_format *input_format, BMediaEncoder::SetFormat(media_format *input_format,
media_format *output_format, media_format *output_format, media_file_format *mfi)
media_file_format *mfi)
{ {
UNIMPLEMENTED(); CALLED();
return B_OK; TRACE("BMediaEncoder::SetFormat. Input = %d, Output = %d\n",
input_format->type, output_format->type);
if (!fEncoder)
return B_NO_INIT;
//TODO: How we support output_format and mfi?
return fEncoder->SetUp(input_format);
} }
status_t status_t
BMediaEncoder::Encode(const void *buffer, BMediaEncoder::Encode(const void *buffer,
int64 frame_count, int64 frame_count, media_encode_info *info)
media_encode_info *info)
{ {
UNIMPLEMENTED(); CALLED();
return B_OK;
if (!fEncoder)
return B_NO_INIT;
return fEncoder->Encode(buffer, frame_count, info);
} }
status_t status_t
BMediaEncoder::GetEncodeParameters(encode_parameters *parameters) const BMediaEncoder::GetEncodeParameters(encode_parameters *parameters) const
{ {
UNIMPLEMENTED(); CALLED();
return B_OK;
if (fEncoder == NULL)
return B_NO_INIT;
else
return fEncoder->GetEncodeParameters(parameters);
} }
status_t status_t
BMediaEncoder::SetEncodeParameters(encode_parameters *parameters) BMediaEncoder::SetEncodeParameters(encode_parameters *parameters)
{ {
UNIMPLEMENTED(); CALLED();
return B_OK;
if (fEncoder == NULL)
return B_NO_INIT;
else
return fEncoder->SetEncodeParameters(parameters);
} }
@@ -101,8 +190,12 @@ BMediaEncoder::SetEncodeParameters(encode_parameters *parameters)
/* virtual */ status_t /* virtual */ status_t
BMediaEncoder::AddTrackInfo(uint32 code, const char *data, size_t size) BMediaEncoder::AddTrackInfo(uint32 code, const char *data, size_t size)
{ {
UNIMPLEMENTED(); CALLED();
return B_OK;
if (fEncoder == NULL)
return B_NO_INIT;
else
return fEncoder->AddTrackInfo(code, data, size);
} }
@@ -117,10 +210,8 @@ BMediaEncoder::BMediaEncoder & operator=(const BMediaEncoder &);
*/ */
/* static */ status_t /* static */ status_t
BMediaEncoder::write_chunk(void *classptr, BMediaEncoder::write_chunk(void* classptr, const void* chunk_data,
const void *chunk_data, size_t chunk_len, media_encode_info* info)
size_t chunk_len,
media_encode_info *info)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
return B_OK; return B_OK;
@@ -140,6 +231,33 @@ BMediaEncoder::ReleaseEncoder()
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
status_t
BMediaEncoder::_AttachToEncoder()
{
class MediaEncoderChunkWriter : public ChunkWriter {
public:
MediaEncoderChunkWriter(BMediaEncoder* encoder)
{
fEncoder = encoder;
}
virtual status_t WriteChunk(const void* chunkBuffer,
size_t chunkSize, media_encode_info* encodeInfo)
{
return fEncoder->WriteChunk(chunkBuffer, chunkSize, encodeInfo);
}
private:
BMediaEncoder* fEncoder;
} *writer = new(std::nothrow) MediaEncoderChunkWriter(this);
if (!writer)
return B_NO_MEMORY;
fEncoder->SetChunkWriter(writer);
return B_OK;
}
status_t BMediaEncoder::_Reserved_BMediaEncoder_0(int32 arg, ...) { return B_ERROR; } status_t BMediaEncoder::_Reserved_BMediaEncoder_0(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_1(int32 arg, ...) { return B_ERROR; } status_t BMediaEncoder::_Reserved_BMediaEncoder_1(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_2(int32 arg, ...) { return B_ERROR; } status_t BMediaEncoder::_Reserved_BMediaEncoder_2(int32 arg, ...) { return B_ERROR; }
@@ -162,33 +280,50 @@ status_t BMediaEncoder::_Reserved_BMediaEncoder_15(int32 arg, ...) { return B_ER
*************************************************************/ *************************************************************/
BMediaBufferEncoder::BMediaBufferEncoder() BMediaBufferEncoder::BMediaBufferEncoder()
:
BMediaEncoder(),
fBuffer(NULL)
{ {
UNIMPLEMENTED(); CALLED();
} }
BMediaBufferEncoder::BMediaBufferEncoder(const media_format *output_format) BMediaBufferEncoder::BMediaBufferEncoder(const media_format *output_format)
:
BMediaEncoder(output_format),
fBuffer(NULL)
{ {
UNIMPLEMENTED(); CALLED();
} }
BMediaBufferEncoder::BMediaBufferEncoder(const media_codec_info *mci) BMediaBufferEncoder::BMediaBufferEncoder(const media_codec_info *mci)
:
BMediaEncoder(mci),
fBuffer(NULL)
{ {
UNIMPLEMENTED(); CALLED();
} }
status_t status_t
BMediaBufferEncoder::EncodeToBuffer(void *output_buffer, BMediaBufferEncoder::EncodeToBuffer(void *output_buffer,
size_t *output_size, size_t *output_size, const void *input_buffer,
const void *input_buffer, int64 frame_count, media_encode_info *info)
int64 frame_count,
media_encode_info *info)
{ {
UNIMPLEMENTED(); CALLED();
return B_ERROR; status_t error;
fBuffer = output_buffer;
fBufferSize = *output_size;
error = Encode(input_buffer, frame_count, info);
if (fBuffer) {
fBuffer = NULL;
*output_size = 0;
} else {
*output_size = fBufferSize;
}
return error;
} }
@@ -198,12 +333,24 @@ BMediaBufferEncoder::EncodeToBuffer(void *output_buffer,
status_t status_t
BMediaBufferEncoder::WriteChunk(const void *chunk_data, BMediaBufferEncoder::WriteChunk(const void *chunk_data,
size_t chunk_len, size_t chunk_len, media_encode_info *info)
media_encode_info *info)
{ {
UNIMPLEMENTED(); CALLED();
return B_ERROR; if (fBuffer == NULL)
return B_ENTRY_NOT_FOUND;
if (chunk_len < 0)
return B_ERROR;
if (chunk_len > (size_t)fBufferSize) {
memcpy(fBuffer, chunk_data, fBufferSize);
fBuffer = NULL;
return B_DEVICE_FULL;
}
memcpy(fBuffer, chunk_data, chunk_len);
fBufferSize = chunk_len;
fBuffer = NULL;
return B_NO_ERROR;
} }
+79 -3
View File
@@ -151,9 +151,40 @@ PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format)
status_t status_t
PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci) PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci)
{ {
// TODO TRACE("PluginManager::CreateDecoder enter\n");
debugger("not implemented"); entry_ref ref;
return B_ERROR; status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id);
if (status != B_OK)
return status;
MediaPlugin* plugin = GetPlugin(ref);
if (plugin == NULL) {
ERROR("PluginManager::CreateDecoder: GetPlugin failed\n");
return B_ERROR;
}
DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
if (decoderPlugin == NULL) {
ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n");
PutPlugin(plugin);
return B_ERROR;
}
// TODO: In theory, one DecoderPlugin could support multiple Decoders,
// but this is not yet handled (passing "0" as index/ID).
*decoder = decoderPlugin->NewDecoder(0);
if (*decoder == NULL) {
ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n");
PutPlugin(plugin);
return B_ERROR;
}
TRACE(" created decoder: %p\n", *decoder);
(*decoder)->fMediaPlugin = plugin;
TRACE("PluginManager::CreateDecoder leave\n");
return B_OK;
} }
@@ -294,6 +325,51 @@ PluginManager::CreateEncoder(Encoder** _encoder,
} }
status_t
PluginManager::CreateEncoder(Encoder** encoder, const media_format& format)
{
TRACE("PluginManager::CreateEncoder enter nr2\n");
entry_ref ref;
status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat(
&ref, format);
if (ret != B_OK) {
ERROR("PluginManager::CreateEncoder: can't get decoder for format: "
"%s\n", strerror(ret));
return ret;
}
MediaPlugin* plugin = GetPlugin(ref);
if (plugin == NULL) {
ERROR("PluginManager::CreateEncoder: GetPlugin failed\n");
return B_ERROR;
}
EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
if (encoderPlugin == NULL) {
ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n");
PutPlugin(plugin);
return B_ERROR;
}
*encoder = encoderPlugin->NewEncoder(format);
if (*encoder == NULL) {
ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n");
PutPlugin(plugin);
return B_ERROR;
}
TRACE(" created encoder: %p\n", *encoder);
(*encoder)->fMediaPlugin = plugin;
TRACE("PluginManager::CreateEncoder leave nr2\n");
return B_OK;
}
void void
PluginManager::DestroyEncoder(Encoder* encoder) PluginManager::DestroyEncoder(Encoder* encoder)
{ {