* 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:
Stephan Aßmus 2009-07-31 15:29:08 +00:00
parent f9acacb7d1
commit 4384acf6c1
7 changed files with 172 additions and 37 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -20,7 +20,7 @@ const media_file_format gMuxerTable[] = {
{ 0 },
"video/x-msvideo",
"AVI (Audio Video Interleaved)",
"AVI",
"avi",
"avi",
{ 0 }
},

View File

@ -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));

View File

@ -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;