Hello all,
this is my first mail to this list. I am trying to create a Demuxer plugin
based on libavformat for the Haiku operating system. Thanks in advance for
any help!
My setup is that I cannot use av_open_input_file() with a regular path to a
file. I've read the nice tutorial at
<http://www.dranger.com/ffmpeg/ffmpeg.html>, and I've also googled a bit
for my problem and found some helpful messages on this list, and I've read
a lot in the libavformat code.
My first attempt was to write a URLProtocol to give libavformat access to
my data stream, and then attempted to use av_open_input_file(...,
"my_protocol:...", ...). Unfortunately, my protocol open hook was never
called, even though I properly registered the protocol and even checked
that via dumping all protocols like this:
URLProtocol* p = NULL;
while ((p = av_protocol_next(p)) != NULL) {
printf("supported protocol: %s\n", p->name);
}
Then after finding a reply in this mailing list for a similar situation, I
tried to setup my own ByteIOContext and AVProdeData. But unfortunately
av_probe_input_format() is not returning an input format for me.
I've attached my code to this mail, it still contains the URLProtocol
attempt as well. I would appreciate a lot if someone could look over this
code and tell me what I might be doing wrong. It should all be in the
AVFormatReader::Sniff() method. To safe some trouble, I am quoting just the
relevant code here:
status_t
AVFormatReader::Sniff(int32* streamCount)
{
TRACE("AVFormatReader::Sniff\n");
size_t bufferSize = 64 * 1024;
uint8 buffer[bufferSize];
AVProbeData probeData;
probeData.filename = "";
probeData.buf = buffer;
probeData.buf_size = bufferSize;
// Read a bit of the input
_ReadPacket(Source(), buffer, bufferSize);
// Probe the input format
AVInputFormat* inputFormat = av_probe_input_format(&probeData, 1);
if (inputFormat == NULL) {
TRACE("AVFormatReader::Sniff() - av_probe_input_format()
failed!\n");
return B_ERROR;
}
TRACE("AVFormatReader::Sniff() - av_probe_input_format(): %s\n",
inputFormat->name);
ByteIOContext ioContext;
// Init io module for input
if (init_put_byte(&ioContext, buffer, bufferSize, 0, Source(),
_ReadPacket, 0, _Seek) != 0) {
TRACE("AVFormatReader::Sniff() - init_put_byte() failed!\n");
return B_ERROR;
}
AVFormatParameters params;
memset(¶ms, 0, sizeof(params));
if (av_open_input_stream(&fContext, &ioContext, "", inputFormat,
¶ms) < 0) {
TRACE("AVFormatReader::Sniff() - av_open_input_file()
failed!\n");
return B_ERROR;
}
TRACE("AVFormatReader::Sniff() - av_open_input_file() success!\n");
// Retrieve stream information
if (av_find_stream_info(fContext) < 0) {
TRACE("AVFormatReader::Sniff() - av_find_stream_info()
failed!\n");
return B_ERROR;
}
TRACE("AVFormatReader::Sniff() - av_find_stream_info() success!\n");
// Dump information about stream onto standard error
dump_format(fContext, 0, "", 0);
return B_ERROR;
}
/*static*/ int
AVFormatReader::_ReadPacket(void* cookie, uint8* buffer, int bufferSize)
{
TRACE("AVFormatReader::_ReadPacket(%p, %p, %d)\n", cookie, buffer,
bufferSize);
BDataIO* dataIO = reinterpret_cast<BDataIO*>(cookie);
ssize_t read = dataIO->Read(buffer, bufferSize);
TRACE(" read: %ld\n", read);
return read;
}
/*static*/ off_t
AVFormatReader::_Seek(void* cookie, off_t offset, int whence)
{
TRACE("AVFormatReader::_Seek(%p, %lld, %d)\n", cookie, offset, whence);
BDataIO* dataIO = reinterpret_cast<BDataIO*>(cookie);
BPositionIO* positionIO = dynamic_cast<BPositionIO*>(dataIO);
if (positionIO == NULL) {
TRACE(" not a BPositionIO\n");
return -1;
}
off_t position = positionIO->Seek(offset, whence);
TRACE(" position: %lld\n", position);
return position;
}
Thanks a lot and best regards,
-Stephan
/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
*/
#ifndef AV_FORMAT_READER_H
#define AV_FORMAT_READER_H
#include "ReaderPlugin.h"
struct AVFormatContext;
class AVFormatReader : public Reader {
public:
AVFormatReader();
~AVFormatReader();
virtual const char* Copyright();
virtual status_t Sniff(int32* streamCount);
virtual void GetFileFormatInfo(media_file_format* mff);
virtual status_t AllocateCookie(int32 streamNumber,
void** cookie);
virtual status_t FreeCookie(void* cookie);
virtual status_t GetStreamInfo(void* cookie, int64* frameCount,
bigtime_t* duration, media_format* format,
const void** infoBuffer,
size_t* infoSize);
virtual status_t Seek(void* cookie, uint32 flags, int64* frame,
bigtime_t* time);
virtual status_t FindKeyFrame(void* cookie, uint32 flags,
int64* frame, bigtime_t* time);
virtual status_t GetNextChunk(void* cookie,
const void** chunkBuffer, size_t* chunkSize,
media_header* mediaHeader);
private:
static int _ReadPacket(void* cookie,
uint8* buffer, int bufferSize);
static off_t _Seek(void* cookie,
off_t offset, int whence);
AVFormatContext* fContext;
};
#endif // AV_FORMAT_READER_H/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
*/
#include "AVFormatReader.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <new>
#include <ByteOrder.h>
#include <DataIO.h>
//#include <InterfaceDefs.h>
#include <MediaFormats.h>
extern "C" {
#include "avformat.h"
#include "libavutil/avstring.h"
}
//#include "RawFormats.h"
#define TRACE_AVFORMAT_READER
#ifdef TRACE_AVFORMAT_READER
# define TRACE printf
#else
# define TRACE(a...)
#endif
#define ERROR(a...) fprintf(stderr, a)
// #pragma mark - BPositionIO protocol
static int
position_io_open(URLContext* h, const char* filename, int flags)
{
TRACE("position_io_open(%s)\n", filename);
// Strip the URL prefix
av_strstart(filename, "position_io:", &filename);
void* pointer;
if (sscanf(filename, "%p", &pointer) != 1) {
TRACE("position_io_open(%s) - unable to scan BPositionIO pointer\n",
filename);
return AVERROR(ENOENT);
}
// When the pointer was placed, it was a BDataIO*. Try to convert that
// into a BPositionIO.
// TODO: Later we may implement two different protocols, one which
// supports seeking (BPositionIO) and one that does not (BDataIO).
BDataIO* dataIO = reinterpret_cast<BDataIO*>(pointer);
BPositionIO* positionIO = dynamic_cast<BPositionIO*>(dataIO);
if (positionIO == NULL) {
TRACE("position_io_open(%s) - unable to cast BDataIO pointer %p\n",
filename, dataIO);
return AVERROR(ENOENT);
}
TRACE("position_io_open(%s) - success: BPositionIO: %p\n",
filename, positionIO);
h->priv_data = reinterpret_cast<void*>(positionIO);
return 0;
}
static int
position_io_read(URLContext* h, unsigned char* buffer, int size)
{
TRACE("position_io_read(%d)\n", size);
BPositionIO* source = reinterpret_cast<BPositionIO*>(h->priv_data);
return source->Read(buffer, size);
}
static int
position_io_write(URLContext* h, unsigned char* buffer, int size)
{
TRACE("position_io_write(%d)\n", size);
BPositionIO* source = reinterpret_cast<BPositionIO*>(h->priv_data);
return source->Write(buffer, size);
}
static int64_t
position_io_seek(URLContext* h, int64_t position, int whence)
{
TRACE("position_io_seek(%lld, %d)\n", position, whence);
BPositionIO* source = reinterpret_cast<BPositionIO*>(h->priv_data);
return source->Seek(position, whence);
}
static int
position_io_close(URLContext* h)
{
TRACE("position_io_close()\n");
// We do not close ourselves here.
return 0;
}
URLProtocol sPositionIOProtocol = {
"position_io",
position_io_open,
position_io_read,
position_io_write,
position_io_seek,
position_io_close
};
// #pragma mark - AVFormatReader
AVFormatReader::AVFormatReader()
:
fContext(NULL)
{
TRACE("AVFormatReader::AVFormatReader\n");
}
AVFormatReader::~AVFormatReader()
{
TRACE("AVFormatReader::~AVFormatReader\n");
// TODO: Deallocate fContext
}
// #pragma mark -
const char*
AVFormatReader::Copyright()
{
// TODO: Return copyright of the file instead!
return "Copyright 2009, Stephan Aßmus";
}
status_t
AVFormatReader::Sniff(int32* streamCount)
{
TRACE("AVFormatReader::Sniff\n");
#if 0
// Construct an URL string that allows us to get the Source()
// BPositionIO pointer and try to open the stream.
char urlString[64];
snprintf(urlString, sizeof(urlString), "position_io:%p", (void*)Source());
if (av_open_input_file(&fContext, urlString, NULL, 0, NULL) < 0) {
TRACE("AVFormatReader::Sniff() - av_open_input_file(%s) failed!\n",
urlString);
return B_ERROR;
}
#else
size_t bufferSize = 64 * 1024;
uint8 buffer[bufferSize];
AVProbeData probeData;
probeData.filename = "";
probeData.buf = buffer;
probeData.buf_size = bufferSize;
// Read a bit of the input
_ReadPacket(Source(), buffer, bufferSize);
// Probe the input format
AVInputFormat* inputFormat = av_probe_input_format(&probeData, 1);
if (inputFormat == NULL) {
TRACE("AVFormatReader::Sniff() - av_probe_input_format() failed!\n");
return B_ERROR;
}
TRACE("AVFormatReader::Sniff() - av_probe_input_format(): %s\n",
inputFormat->name);
ByteIOContext ioContext;
// Init io module for input
if (init_put_byte(&ioContext, buffer, bufferSize, 0, Source(),
_ReadPacket, 0, _Seek) != 0) {
TRACE("AVFormatReader::Sniff() - init_put_byte() failed!\n");
return B_ERROR;
}
AVFormatParameters params;
memset(¶ms, 0, sizeof(params));
if (av_open_input_stream(&fContext, &ioContext, "", inputFormat,
¶ms) < 0) {
TRACE("AVFormatReader::Sniff() - av_open_input_file() failed!\n");
return B_ERROR;
}
#endif
TRACE("AVFormatReader::Sniff() - av_open_input_file() success!\n");
// Retrieve stream information
if (av_find_stream_info(fContext) < 0) {
TRACE("AVFormatReader::Sniff() - av_find_stream_info() failed!\n");
return B_ERROR;
}
TRACE("AVFormatReader::Sniff() - av_find_stream_info() success!\n");
// Dump information about stream onto standard error
dump_format(fContext, 0, "", 0);
return B_ERROR;
}
void
AVFormatReader::GetFileFormatInfo(media_file_format* mff)
{
TRACE("AVFormatReader::GetFileFormatInfo\n");
mff->capabilities = media_file_format::B_READABLE
| media_file_format::B_KNOWS_ENCODED_VIDEO
| media_file_format::B_KNOWS_ENCODED_AUDIO
| media_file_format::B_IMPERFECTLY_SEEKABLE;
mff->family = B_MISC_FORMAT_FAMILY;
mff->version = 100;
strcpy(mff->mime_type, "video/mpg");
strcpy(mff->file_extension, "mpg");
strcpy(mff->short_name, "MPEG");
strcpy(mff->pretty_name, "MPEG (Motion Picture Experts Group)");
}
// #pragma mark -
status_t
AVFormatReader::AllocateCookie(int32 streamNumber, void** _cookie)
{
TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamNumber);
return B_ERROR;
}
status_t
AVFormatReader::FreeCookie(void *_cookie)
{
return B_ERROR;
}
// #pragma mark -
status_t
AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
bigtime_t* duration, media_format* format, const void** infoBuffer,
size_t* infoSize)
{
return B_ERROR;
}
status_t
AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame,
bigtime_t* time)
{
return B_ERROR;
}
status_t
AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame,
bigtime_t* time)
{
return B_ERROR;
}
status_t
AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer,
size_t* chunkSize, media_header* mediaHeader)
{
return B_ERROR;
}
// #pragma mark -
/*static*/ int
AVFormatReader::_ReadPacket(void* cookie, uint8* buffer, int bufferSize)
{
TRACE("AVFormatReader::_ReadPacket(%p, %p, %d)\n", cookie, buffer,
bufferSize);
BDataIO* dataIO = reinterpret_cast<BDataIO*>(cookie);
ssize_t read = dataIO->Read(buffer, bufferSize);
TRACE(" read: %ld\n", read);
return read;
}
/*static*/ off_t
AVFormatReader::_Seek(void* cookie, off_t offset, int whence)
{
TRACE("AVFormatReader::_Seek(%p, %lld, %d)\n", cookie, offset, whence);
BDataIO* dataIO = reinterpret_cast<BDataIO*>(cookie);
BPositionIO* positionIO = dynamic_cast<BPositionIO*>(dataIO);
if (positionIO == NULL) {
TRACE(" not a BPositionIO\n");
return -1;
}
off_t position = positionIO->Seek(offset, whence);
TRACE(" position: %lld\n", position);
return position;
}
/*
* Copyright (C) 2001 Carlos Hasan
* Copyright (C) 2001 François Revol
* Copyright (C) 2001 Axel Dörfler
* Copyright (C) 2004 Marcus Overhagen
* Copyright (C) 2009 Stephan Aßmus <[email protected]>
*
* All rights reserved. Distributed under the terms of the MIT License.
*/
//! libavcodec/libavformat based Decoder and Reader plugin for Haiku
#include "FFmpegPlugin.h"
#include <stdio.h>
#include <new>
extern "C" {
#include "avformat.h"
}
#include "AVCodecDecoder.h"
#include "AVFormatReader.h"
#include "CodecTable.h"
FFmpegPlugin::GlobalInitilizer::GlobalInitilizer()
{
av_register_all();
// This will also call av_codec_init() by registering codecs.
extern URLProtocol sPositionIOProtocol;
av_register_protocol(&sPositionIOProtocol);
// // Dump the supported protocols to stdout.
// URLProtocol* p = NULL;
// while ((p = av_protocol_next(p)) != NULL) {
// printf("supported protocol: %s\n", p->name);
// }
}
FFmpegPlugin::GlobalInitilizer::~GlobalInitilizer()
{
// TODO: uninit anything here?
}
FFmpegPlugin::GlobalInitilizer FFmpegPlugin::sInitilizer;
// #pragma mark -
Decoder*
FFmpegPlugin::NewDecoder(uint index)
{
// TODO: Confirm we can check index here.
// if (index == 0)
return new(std::nothrow) AVCodecDecoder();
// return NULL;
}
Reader*
FFmpegPlugin::NewReader()
{
return new(std::nothrow) AVFormatReader();
}
status_t
FFmpegPlugin::GetSupportedFormats(media_format** formats, size_t* count)
{
BMediaFormats mediaFormats;
if (mediaFormats.InitCheck() != B_OK)
return B_ERROR;
for (int i = 0; i < gCodecCount; i++) {
media_format_description description;
description.family = gCodecTable[i].family;
switch(description.family) {
case B_WAV_FORMAT_FAMILY:
description.u.wav.codec = gCodecTable[i].fourcc;
break;
case B_AIFF_FORMAT_FAMILY:
description.u.aiff.codec = gCodecTable[i].fourcc;
break;
case B_AVI_FORMAT_FAMILY:
description.u.avi.codec = gCodecTable[i].fourcc;
break;
case B_MPEG_FORMAT_FAMILY:
description.u.mpeg.id = gCodecTable[i].fourcc;
break;
case B_QUICKTIME_FORMAT_FAMILY:
description.u.quicktime.codec = gCodecTable[i].fourcc;
break;
case B_MISC_FORMAT_FAMILY:
description.u.misc.file_format =
(uint32)(gCodecTable[i].fourcc >> 32);
description.u.misc.codec = (uint32) gCodecTable[i].fourcc;
break;
default:
break;
}
media_format format;
format.type = gCodecTable[i].type;
format.require_flags = 0;
format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
if (mediaFormats.MakeFormatFor(&description, 1, &format) != B_OK)
return B_ERROR;
gAVCodecFormats[i] = format;
}
*formats = gAVCodecFormats;
*count = gCodecCount;
return B_OK;
}
MediaPlugin*
instantiate_plugin()
{
return new(std::nothrow) FFmpegPlugin;
}
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user