* Tweaked the Writer API. Basically, we need an Init() method that takes the
media_file_format as input, so that the Writer knows what kind of file is needed. * Also, since information about the stream format is going to be needed at the Writer level as well, the AllocateCookie() method gets the stream media_format. * Fleshed out some aspects of AVFormatWriter, many TODOs are left. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32025 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
f9acacb7d1
commit
4384acf6c1
@ -27,6 +27,7 @@ public:
|
||||
|
||||
status_t CreateEncoder(Encoder** _encoder,
|
||||
const media_codec_info* codecInfo,
|
||||
const media_format* format,
|
||||
uint32 flags = 0);
|
||||
|
||||
status_t SetCopyright(int32 streamIndex,
|
||||
|
@ -13,12 +13,15 @@ public:
|
||||
Writer();
|
||||
virtual ~Writer();
|
||||
|
||||
virtual status_t Init(const media_file_format* fileFormat) = 0;
|
||||
|
||||
virtual status_t SetCopyright(const char* copyright) = 0;
|
||||
virtual status_t CommitHeader() = 0;
|
||||
virtual status_t Flush() = 0;
|
||||
virtual status_t Close() = 0;
|
||||
|
||||
virtual status_t AllocateCookie(void** cookie) = 0;
|
||||
virtual status_t AllocateCookie(void** cookie,
|
||||
const media_format* format) = 0;
|
||||
virtual status_t FreeCookie(void* cookie) = 0;
|
||||
|
||||
virtual status_t SetCopyright(void* cookie,
|
||||
|
@ -40,18 +40,36 @@ extern "C" {
|
||||
#define ERROR(a...) fprintf(stderr, a)
|
||||
|
||||
|
||||
static const size_t kIOBufferSize = 64 * 1024;
|
||||
// TODO: This could depend on the BMediaFile creation flags, IIRC,
|
||||
// they allow to specify a buffering mode.
|
||||
|
||||
|
||||
// #pragma mark - URLProtocol
|
||||
// TODO: Do we need to write an URLProtocol?
|
||||
|
||||
|
||||
// #pragma mark - AVFormatWriter::StreamCookie
|
||||
|
||||
|
||||
class AVFormatWriter::StreamCookie {
|
||||
public:
|
||||
StreamCookie(BPositionIO* target,
|
||||
StreamCookie(AVFormatContext* context,
|
||||
BLocker* streamLock);
|
||||
virtual ~StreamCookie();
|
||||
|
||||
status_t Init(const media_format* format);
|
||||
|
||||
status_t WriteChunk(const void* chunkBuffer,
|
||||
size_t chunkSize,
|
||||
media_encode_info* encodeInfo);
|
||||
|
||||
status_t AddTrackInfo(uint32 code, const void* data,
|
||||
size_t size, uint32 flags);
|
||||
|
||||
private:
|
||||
BPositionIO* fTarget;
|
||||
off_t fPosition;
|
||||
AVFormatContext* fContext;
|
||||
AVStream* fStream;
|
||||
// Since different threads may read from the source,
|
||||
// we need to protect the file position and I/O by a lock.
|
||||
BLocker* fStreamLock;
|
||||
@ -59,11 +77,11 @@ private:
|
||||
|
||||
|
||||
|
||||
AVFormatWriter::StreamCookie::StreamCookie(BPositionIO* target,
|
||||
AVFormatWriter::StreamCookie::StreamCookie(AVFormatContext* context,
|
||||
BLocker* streamLock)
|
||||
:
|
||||
fTarget(target),
|
||||
fPosition(0),
|
||||
fContext(context),
|
||||
fStream(NULL),
|
||||
fStreamLock(streamLock)
|
||||
{
|
||||
}
|
||||
@ -74,12 +92,60 @@ AVFormatWriter::StreamCookie::~StreamCookie()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::StreamCookie::Init(const media_format* format)
|
||||
{
|
||||
TRACE("AVFormatWriter::StreamCookie::Init()\n");
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
fStream = av_new_stream(fContext, fContext->nb_streams);
|
||||
|
||||
if (fStream == NULL) {
|
||||
TRACE(" failed to add new stream\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// TODO: Setup the stream according to the media format...
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
||||
size_t chunkSize, media_encode_info* encodeInfo)
|
||||
{
|
||||
TRACE("AVFormatWriter::StreamCookie::WriteChunk(%p, %ld)\n",
|
||||
chunkBuffer, chunkSize);
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::StreamCookie::AddTrackInfo(uint32 code,
|
||||
const void* data, size_t size, uint32 flags)
|
||||
{
|
||||
TRACE("AVFormatWriter::StreamCookie::AddTrackInfo(%lu, %p, %ld, %lu)\n",
|
||||
code, data, size, flags);
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AVFormatWriter
|
||||
|
||||
|
||||
AVFormatWriter::AVFormatWriter()
|
||||
:
|
||||
fStreams(NULL),
|
||||
fContext(avformat_alloc_context()),
|
||||
fHeaderWritten(false),
|
||||
fIOBuffer(NULL),
|
||||
fStreamLock("stream lock")
|
||||
{
|
||||
TRACE("AVFormatWriter::AVFormatWriter\n");
|
||||
@ -89,16 +155,55 @@ AVFormatWriter::AVFormatWriter()
|
||||
AVFormatWriter::~AVFormatWriter()
|
||||
{
|
||||
TRACE("AVFormatWriter::~AVFormatWriter\n");
|
||||
if (fStreams != NULL) {
|
||||
delete fStreams[0];
|
||||
delete[] fStreams;
|
||||
}
|
||||
|
||||
av_free(fContext);
|
||||
|
||||
delete[] fIOBuffer;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::Init(const media_file_format* fileFormat)
|
||||
{
|
||||
TRACE("AVFormatWriter::Init()\n");
|
||||
|
||||
delete[] fIOBuffer;
|
||||
fIOBuffer = new(std::nothrow) uint8[kIOBufferSize];
|
||||
if (fIOBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// Init I/O context with buffer and hook functions, pass ourself as
|
||||
// cookie.
|
||||
if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, this,
|
||||
0, _Write, _Seek) != 0) {
|
||||
TRACE(" init_put_byte() failed!\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// TODO: Is this how it works?
|
||||
// TODO: Is the cookie stored in ByteIOContext? Or does it need to be
|
||||
// stored in fContext->priv_data?
|
||||
fContext->pb = &fIOContext;
|
||||
|
||||
// TODO: Set the AVOutputFormat according to fileFormat...
|
||||
fContext->oformat = guess_format(fileFormat->short_name,
|
||||
fileFormat->file_extension, fileFormat->mime_type);
|
||||
if (fContext->oformat == NULL) {
|
||||
TRACE(" failed to find AVOuputFormat for %s\n",
|
||||
fileFormat->short_name);
|
||||
return B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
TRACE(" found AVOuputFormat for %s: %s\n", fileFormat->short_name,
|
||||
fContext->oformat->name);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::SetCopyright(const char* copyright)
|
||||
{
|
||||
@ -113,7 +218,19 @@ AVFormatWriter::CommitHeader()
|
||||
{
|
||||
TRACE("AVFormatWriter::CommitHeader\n");
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
if (fContext == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
if (fHeaderWritten)
|
||||
return B_NOT_ALLOWED;
|
||||
|
||||
int result = av_write_header(fContext);
|
||||
if (result < 0)
|
||||
TRACE(" av_write_header(): %d\n", result);
|
||||
else
|
||||
fHeaderWritten = true;
|
||||
|
||||
return result == 0 ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -131,24 +248,34 @@ AVFormatWriter::Close()
|
||||
{
|
||||
TRACE("AVFormatWriter::Close\n");
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
if (fContext == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
if (!fHeaderWritten)
|
||||
return B_NOT_ALLOWED;
|
||||
|
||||
int result = av_write_trailer(fContext);
|
||||
if (result < 0)
|
||||
TRACE(" av_write_trailer(): %d\n", result);
|
||||
|
||||
return result == 0 ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::AllocateCookie(void** _cookie)
|
||||
AVFormatWriter::AllocateCookie(void** _cookie, const media_format* format)
|
||||
{
|
||||
TRACE("AVFormatWriter::AllocateCookie()\n");
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
if (fStreams == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
if (_cookie == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
StreamCookie* cookie = new(std::nothrow) StreamCookie(fContext,
|
||||
&fStreamLock);
|
||||
|
||||
return cookie->Init(format);
|
||||
}
|
||||
|
||||
|
||||
@ -158,12 +285,7 @@ AVFormatWriter::FreeCookie(void* _cookie)
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
||||
|
||||
if (cookie != NULL) {
|
||||
// if (fStreams != NULL)
|
||||
// fStreams[cookie->VirtualIndex()] = NULL;
|
||||
delete cookie;
|
||||
}
|
||||
delete cookie;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -182,24 +304,26 @@ AVFormatWriter::SetCopyright(void* cookie, const char* copyright)
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::AddTrackInfo(void* cookie, uint32 code,
|
||||
AVFormatWriter::AddTrackInfo(void* _cookie, uint32 code,
|
||||
const void* data, size_t size, uint32 flags)
|
||||
{
|
||||
TRACE("AVFormatWriter::AddTrackInfo(%lu, %p, %ld, %lu)\n",
|
||||
code, data, size, flags);
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
||||
return cookie->AddTrackInfo(code, data, size, flags);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatWriter::WriteChunk(void* cookie, const void* chunkBuffer,
|
||||
AVFormatWriter::WriteChunk(void* _cookie, const void* chunkBuffer,
|
||||
size_t chunkSize, media_encode_info* encodeInfo)
|
||||
{
|
||||
TRACE("AVFormatWriter::WriteChunk(%p, %ld, %p)\n", chunkBuffer, chunkSize,
|
||||
encodeInfo);
|
||||
|
||||
return B_NOT_SUPPORTED;
|
||||
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
||||
return cookie->WriteChunk(chunkBuffer, chunkSize, encodeInfo);
|
||||
}
|
||||
|
||||
|
||||
@ -234,8 +358,7 @@ AVFormatWriter::_Seek(void* cookie, off_t offset, int whence)
|
||||
if (positionIO == NULL)
|
||||
return -1;
|
||||
|
||||
// Support for special file size retrieval API without seeking
|
||||
// anywhere:
|
||||
// Support for special file size retrieval API without seeking anywhere:
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
off_t size;
|
||||
if (positionIO->GetSize(&size) == B_OK)
|
||||
|
@ -20,12 +20,15 @@ public:
|
||||
AVFormatWriter();
|
||||
~AVFormatWriter();
|
||||
|
||||
virtual status_t Init(const media_file_format* fileFormat);
|
||||
|
||||
virtual status_t SetCopyright(const char* copyright);
|
||||
virtual status_t CommitHeader();
|
||||
virtual status_t Flush();
|
||||
virtual status_t Close();
|
||||
|
||||
virtual status_t AllocateCookie(void** cookie);
|
||||
virtual status_t AllocateCookie(void** cookie,
|
||||
const media_format* format);
|
||||
virtual status_t FreeCookie(void* cookie);
|
||||
|
||||
virtual status_t SetCopyright(void* cookie,
|
||||
@ -49,6 +52,10 @@ private:
|
||||
class StreamCookie;
|
||||
|
||||
AVFormatContext* fContext;
|
||||
bool fHeaderWritten;
|
||||
|
||||
ByteIOContext fIOContext;
|
||||
uint8* fIOBuffer;
|
||||
|
||||
StreamCookie** fStreams;
|
||||
BLocker fStreamLock;
|
||||
|
@ -20,7 +20,7 @@ const media_file_format gMuxerTable[] = {
|
||||
{ 0 },
|
||||
"video/x-msvideo",
|
||||
"AVI (Audio Video Interleaved)",
|
||||
"AVI",
|
||||
"avi",
|
||||
"avi",
|
||||
{ 0 }
|
||||
},
|
||||
|
@ -732,7 +732,7 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
|
||||
SetupWorkaround();
|
||||
|
||||
if (codecInfo != NULL) {
|
||||
status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo);
|
||||
status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format);
|
||||
if (ret != B_OK) {
|
||||
TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
|
||||
"%s\n", strerror(ret));
|
||||
|
@ -78,7 +78,7 @@ MediaWriter::InitCheck()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
return fWriter != NULL ? B_OK : B_NO_INIT;
|
||||
return fWriter != NULL ? fWriter->Init(&fFileFormat) : B_NO_INIT;
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,8 @@ MediaWriter::GetFileFormatInfo(media_file_format* _fileFormat) const
|
||||
|
||||
status_t
|
||||
MediaWriter::CreateEncoder(Encoder** _encoder,
|
||||
const media_codec_info* codecInfo, uint32 flags)
|
||||
const media_codec_info* codecInfo, const media_format* format,
|
||||
uint32 flags)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
@ -109,7 +110,7 @@ MediaWriter::CreateEncoder(Encoder** _encoder,
|
||||
}
|
||||
|
||||
StreamInfo info;
|
||||
ret = fWriter->AllocateCookie(&info.cookie);
|
||||
ret = fWriter->AllocateCookie(&info.cookie, format);
|
||||
if (ret != B_OK) {
|
||||
_plugin_manager.DestroyEncoder(encoder);
|
||||
return ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user