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(&params, 0, sizeof(params));

        if (av_open_input_stream(&fContext, &ioContext, "", inputFormat,
                &params) < 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(&params, 0, sizeof(params));

	if (av_open_input_stream(&fContext, &ioContext, "", inputFormat,
		&params) < 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

Reply via email to