* Fleshed out some more of the format detection.

* Moved stuff from testing in Sniff() into class members.
* Added function to gfx_utils() that converts an FFmpeg pix_fmt to color_space.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31402 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-07-03 21:40:19 +00:00
parent 55108a8e90
commit 827faf77a4
4 changed files with 286 additions and 33 deletions

View File

@ -13,13 +13,10 @@
#include <ByteOrder.h>
#include <DataIO.h>
//#include <InterfaceDefs.h>
#include <MediaDefs.h>
#include <MediaFormats.h>
extern "C" {
#include "avformat.h"
#include "libavutil/avstring.h"
}
#include "gfx_util.h"
//#include "RawFormats.h"
@ -36,11 +33,18 @@ 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,
// the allow to specify a buffering mode.
AVFormatReader::AVFormatReader()
:
fContext(NULL)
fContext(NULL),
fIOBuffer(NULL)
{
TRACE("AVFormatReader::AVFormatReader\n");
memset(&fFormatParameters, 0, sizeof(fFormatParameters));
}
@ -48,7 +52,8 @@ AVFormatReader::~AVFormatReader()
{
TRACE("AVFormatReader::~AVFormatReader\n");
// TODO: Deallocate fContext
av_free(fContext);
free(fIOBuffer);
}
@ -68,16 +73,17 @@ AVFormatReader::Sniff(int32* streamCount)
{
TRACE("AVFormatReader::Sniff\n");
size_t bufferSize = 64 * 1024;
free(fIOBuffer);
fIOBuffer = (uint8*)malloc(kIOBufferSize);
size_t probeSize = 1024;
uint8 buffer[bufferSize];
AVProbeData probeData;
probeData.filename = "";
probeData.buf = buffer;
probeData.buf = fIOBuffer;
probeData.buf_size = probeSize;
// Read a bit of the input...
if (_ReadPacket(Source(), buffer, probeSize) != (ssize_t)probeSize)
if (_ReadPacket(Source(), fIOBuffer, probeSize) != (ssize_t)probeSize)
return B_IO_ERROR;
// ...and seek back to the beginning of the file.
_Seek(Source(), 0, SEEK_SET);
@ -93,20 +99,15 @@ AVFormatReader::Sniff(int32* streamCount)
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(),
// Init I/O context with buffer and hook functions
if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, Source(),
_ReadPacket, 0, _Seek) != 0) {
TRACE("AVFormatReader::Sniff() - init_put_byte() failed!\n");
return B_ERROR;
}
AVFormatParameters formatParameters;
memset(&formatParameters, 0, sizeof(formatParameters));
if (av_open_input_stream(&fContext, &ioContext, "", inputFormat,
&formatParameters) < 0) {
if (av_open_input_stream(&fContext, &fIOContext, "", inputFormat,
&fFormatParameters) < 0) {
TRACE("AVFormatReader::Sniff() - av_open_input_stream() failed!\n");
return B_ERROR;
}
@ -122,7 +123,11 @@ AVFormatReader::Sniff(int32* streamCount)
// Dump information about stream onto standard error
dump_format(fContext, 0, "", 0);
return B_ERROR;
if (streamCount != NULL)
*streamCount = fContext->nb_streams;
// return B_OK;
return B_ERROR; // For now...
}
@ -131,16 +136,41 @@ AVFormatReader::GetFileFormatInfo(media_file_format* mff)
{
TRACE("AVFormatReader::GetFileFormatInfo\n");
if (fContext == NULL || fContext->iformat == NULL) {
TRACE(" no context or AVInputFormat!\n");
return;
}
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)");
strcpy(mff->mime_type, "");
// TODO: Would be nice to be able to provide this, maybe by extending
// the FFmpeg code itself (all demuxers, see AVInputFormat struct).
if (fContext->iformat->extensions != NULL)
strcpy(mff->file_extension, fContext->iformat->extensions);
else {
TRACE(" no file extensions for AVInputFormat.\n");
strcpy(mff->file_extension, "");
}
if (fContext->iformat->name != NULL)
strcpy(mff->short_name, fContext->iformat->name);
else {
TRACE(" no short name for AVInputFormat.\n");
strcpy(mff->short_name, "");
}
if (fContext->iformat->long_name != NULL)
strcpy(mff->pretty_name, fContext->iformat->long_name);
else {
TRACE(" no long name for AVInputFormat.\n");
strcpy(mff->pretty_name, "");
}
}
@ -148,18 +178,132 @@ AVFormatReader::GetFileFormatInfo(media_file_format* mff)
status_t
AVFormatReader::AllocateCookie(int32 streamNumber, void** _cookie)
AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie)
{
TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamNumber);
TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex);
return B_ERROR;
if (fContext == NULL)
return B_NO_INIT;
if (streamIndex < 0 || streamIndex >= (int32)fContext->nb_streams)
return B_BAD_INDEX;
if (_cookie == NULL)
return B_BAD_VALUE;
StreamCookie* cookie = new(std::nothrow) StreamCookie;
if (cookie == NULL)
return B_NO_MEMORY;
// Get a pointer to the codec context for the stream at sreamIndex.
AVCodecContext* codecContext = fContext->streams[streamIndex]->codec;
AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
if (codec == NULL || avcodec_open(codecContext, codec) < 0) {
delete cookie;
return B_ERROR;
}
// codecContext->get_buffer = _GetBuffer;
// codecContext->release_buffer = _ReleaseBuffer;
AVStream* stream = fContext->streams[streamIndex];
cookie->stream = stream;
cookie->codecContext = codecContext;
cookie->codec = codec;
media_format* format = &cookie->format;
memset(format, 0, sizeof(media_format));
BMediaFormats formats;
media_format_description description;
if (stream->codec->codec_type == CODEC_TYPE_VIDEO) {
// TODO: Fix this up! Maybe do this for AVI demuxer and MOV
// demuxer and use B_MISC_FORMAT_FAMILY for all the others?
description.family = B_AVI_FORMAT_FAMILY;
description.u.avi.codec = codecContext->codec_tag;
TRACE(" fourcc '%.4s'\n", (char*)&codecContext->codec_tag);
if (formats.GetFormatFor(description, format) < B_OK)
format->type = B_MEDIA_ENCODED_VIDEO;
// format->require_flags =
// format->deny_flags =
format->user_data_type = B_CODEC_TYPE_INFO;
*(uint32*)format->user_data = codecContext->codec_tag;
format->user_data[4] = 0;
// TODO: We don't actually know the bitrate for this stream,
// only the total bitrate!
format->u.encoded_video.avg_bit_rate = codecContext->bit_rate;
format->u.encoded_video.max_bit_rate = codecContext->bit_rate
+ codecContext->bit_rate_tolerance;
format->u.encoded_video.encoding = media_encoded_video_format::B_ANY;
format->u.encoded_video.frame_size = 1;
// format->u.encoded_video.forward_history = 0;
// format->u.encoded_video.backward_history = 0;
format->u.encoded_video.output.field_rate
= av_q2d(stream->r_frame_rate);
format->u.encoded_video.output.interlace = 1;
// TODO: Fix up for interlaced video
format->u.encoded_video.output.first_active = 0;
format->u.encoded_video.output.last_active = 0;
// TODO: Maybe libavformat actually provides that info somewhere...
format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
// TODO: Implement aspect ratio for real
format->u.encoded_video.output.pixel_width_aspect
= 1;//stream->sample_aspect_ratio.num;
format->u.encoded_video.output.pixel_height_aspect
= 1;//stream->sample_aspect_ratio.den;
TRACE(" pixel width/height aspect: %d/%d or %.4f\n",
stream->sample_aspect_ratio.num,
stream->sample_aspect_ratio.den,
av_q2d(stream->sample_aspect_ratio));
format->u.encoded_video.output.display.format
= pixfmt_to_colorspace(codecContext->pix_fmt);
format->u.encoded_video.output.display.line_width = codecContext->width;
format->u.encoded_video.output.display.line_count = codecContext->height;
format->u.encoded_video.output.display.bytes_per_row = 0;
format->u.encoded_video.output.display.pixel_offset = 0;
format->u.encoded_video.output.display.line_offset = 0;
format->u.encoded_video.output.display.flags = 0; // TODO
uint32 encoding = format->Encoding();
TRACE(" encoding '%.4s'\n", (char*)&encoding);
} else if (stream->codec->codec_type == CODEC_TYPE_AUDIO) {
format->type = B_MEDIA_ENCODED_AUDIO;
// format->require_flags =
// format->deny_flags =
// format->u.encoded_audio.
} else {
return B_NOT_SUPPORTED;
}
*_cookie = cookie;
return B_OK;
}
status_t
AVFormatReader::FreeCookie(void *_cookie)
{
return B_ERROR;
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
avcodec_close(cookie->codecContext);
delete cookie;
return B_OK;
}
@ -171,7 +315,35 @@ AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
bigtime_t* duration, media_format* format, const void** infoBuffer,
size_t* infoSize)
{
return B_ERROR;
TRACE("AVFormatReader::GetStreamInfo()\n");
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
AVStream* stream = cookie->stream;
double frameRate = av_q2d(stream->r_frame_rate);
TRACE(" frameRate: %.4f\n", frameRate);
*duration = (bigtime_t)(1000000LL * stream->duration
* av_q2d(stream->time_base));
TRACE(" duration: %lld\n", *duration);
*frameCount = stream->nb_frames;
if (*frameCount == 0) {
// TODO: Calculate from duration and frame rate!
*frameCount = (int64)(*duration * frameRate / 1000000);
}
TRACE(" frameCount: %lld\n", *frameCount);
*format = cookie->format;
// TODO: Possibly use stream->metadata for this:
*infoBuffer = 0;
*infoSize = 0;
return B_OK;
}

View File

@ -8,8 +8,9 @@
#include "ReaderPlugin.h"
struct AVFormatContext;
extern "C" {
#include "avformat.h"
}
class AVFormatReader : public Reader {
@ -49,6 +50,20 @@ private:
off_t offset, int whence);
AVFormatContext* fContext;
AVFormatParameters fFormatParameters;
ByteIOContext fIOContext;
uint8* fIOBuffer;
struct StreamCookie {
AVStream* stream;
AVCodecContext* codecContext;
AVCodec* codec;
media_format format;
// TODO: Maybe we don't need the codec after all, maybe we do
// for getting stream information...
// TODO: Some form of packet queue
};
};

View File

@ -146,7 +146,8 @@ gfx_convert_func resolve_colorspace(color_space colorSpace, PixelFormat pixelFor
}
}
const char *pixfmt_to_string(int p)
const char*
pixfmt_to_string(int p)
{
switch(p) {
case PIX_FMT_NONE: return "PIX_FMT_NONE";
@ -205,6 +206,69 @@ const char *pixfmt_to_string(int p)
}
}
color_space
pixfmt_to_colorspace(int p)
{
switch(p) {
default:
case PIX_FMT_NONE:
return B_NO_COLOR_SPACE;
case PIX_FMT_YUV420P: return B_YUV420; ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
case PIX_FMT_YUYV422: return B_YUV422; ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
case PIX_FMT_RGB24: return B_RGB24_BIG; ///< packed RGB 8:8:8, 24bpp, RGBRGB...
case PIX_FMT_BGR24: return B_RGB24; ///< packed RGB 8:8:8, 24bpp, BGRBGR...
case PIX_FMT_YUV422P: return B_YUV422; ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
case PIX_FMT_YUV444P: return B_YUV444; ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
case PIX_FMT_RGB32: return B_RGBA32_BIG; ///< packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in CPU endianness
case PIX_FMT_YUV410P: return B_YUV9; ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
case PIX_FMT_YUV411P: return B_YUV12; ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
case PIX_FMT_RGB565: return B_RGB16_BIG; ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in CPU endianness
case PIX_FMT_RGB555: return B_RGB15_BIG; ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in CPU endianness, most significant bit to 0
case PIX_FMT_GRAY8: return B_GRAY8; ///< Y , 8bpp
// case PIX_FMT_MONOWHITE: return B_GRAY1; ///< Y , 1bpp, 0 is white, 1 is black
case PIX_FMT_MONOBLACK: return B_GRAY1; ///< Y , 1bpp, 0 is black, 1 is white
case PIX_FMT_PAL8: return B_CMAP8; ///< 8 bit with PIX_FMT_RGB32 palette
// case PIX_FMT_YUVJ420P: return "PIX_FMT_YUVJ420P - YUV420P (Jpeg)"; ///< planar YUV 4:2:0, 12bpp, full scale (JPEG)
// case PIX_FMT_YUVJ422P: return "PIX_FMT_YUVJ422P - YUV422P (Jpeg)"; ///< planar YUV 4:2:2, 16bpp, full scale (JPEG)
// case PIX_FMT_YUVJ444P: return "PIX_FMT_YUVJ444P"; ///< planar YUV 4:4:4, 24bpp, full scale (JPEG)
// case PIX_FMT_XVMC_MPEG2_MC: return "PIX_FMT_XVMC_MPEG2_MC";///< XVideo Motion Acceleration via common packet passing
// case PIX_FMT_XVMC_MPEG2_IDCT: return "PIX_FMT_XVMC_MPEG2_IDCT";
// case PIX_FMT_UYVY422: return "PIX_FMT_UYVY422"; ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
// case PIX_FMT_UYYVYY411: return "PIX_FMT_UYYVYY411"; ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
case PIX_FMT_BGR32: return B_RGB32; ///< packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in CPU endianness
case PIX_FMT_BGR565: return B_RGB16; ///< packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in CPU endianness
case PIX_FMT_BGR555: return B_RGB15; ///< packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in CPU endianness, most significant bit to 1
// case PIX_FMT_BGR8: return "PIX_FMT_BGR8"; ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
// case PIX_FMT_BGR4: return "PIX_FMT_BGR4"; ///< packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb)
// case PIX_FMT_BGR4_BYTE: return "PIX_FMT_BGR4_BYTE"; ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb)
// case PIX_FMT_RGB8: return "PIX_FMT_RGB8"; ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
// case PIX_FMT_RGB4: return "PIX_FMT_RGB4"; ///< packed RGB 1:2:1, 4bpp, (msb)1R 2G 1B(lsb)
// case PIX_FMT_RGB4_BYTE: return "PIX_FMT_RGB4_BYTE"; ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb)
// case PIX_FMT_NV12: return "PIX_FMT_NV12"; ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV
// case PIX_FMT_NV21: return "PIX_FMT_NV21"; ///< as above, but U and V bytes are swapped
// case PIX_FMT_RGB32_1: return "PIX_FMT_RGB32_1"; ///< packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in CPU endianness
// case PIX_FMT_BGR32_1: return "PIX_FMT_BGR32_1"; ///< packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in CPU endianness
// case PIX_FMT_GRAY16BE: return "PIX_FMT_GRAY16BE"; ///< Y , 16bpp, big-endian
// case PIX_FMT_GRAY16LE: return "PIX_FMT_GRAY16LE"; ///< Y , 16bpp, little-endian
// case PIX_FMT_YUV440P: return "PIX_FMT_YUV440P"; ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
// case PIX_FMT_YUVJ440P: return "PIX_FMT_YUVJ440P - YUV440P (Jpeg)"; ///< planar YUV 4:4:0 full scale (JPEG)
// case PIX_FMT_YUVA420P: return "PIX_FMT_YUVA420P - YUV420P (Alpha)"; ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
// case PIX_FMT_VDPAU_H264: return "PIX_FMT_VDPAU_H264";///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
// case PIX_FMT_VDPAU_MPEG1: return "PIX_FMT_VDPAU_MPEG1";///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
// case PIX_FMT_VDPAU_MPEG2: return "PIX_FMT_VDPAU_MPEG2";///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
// case PIX_FMT_VDPAU_WMV3: return "PIX_FMT_VDPAU_WMV3";///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
// case PIX_FMT_VDPAU_VC1: return "PIX_FMT_VDPAU_VC1"; ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
// case PIX_FMT_RGB48BE: return "PIX_FMT_RGB48BE"; ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, big-endian
// case PIX_FMT_RGB48LE: return "PIX_FMT_RGB48LE"; ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, little-endian
// case PIX_FMT_VAAPI_MOCO: return "PIX_FMT_VAAPI_MOCO"; ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[0] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers
// case PIX_FMT_VAAPI_IDCT: return "PIX_FMT_VAAPI_IDCT"; ///< HW acceleration through VA API at IDCT entry-point, Picture.data[0] contains a vaapi_render_state struct which contains fields extracted from headers
// case PIX_FMT_VAAPI_VLD: return "PIX_FMT_VAAPI_VLD"; ///< HW decoding through VA API, Picture.data[0] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers
}
}
#define BEGIN_TAG "\033[31m"
#define END_TAG "\033[0m"

View File

@ -36,6 +36,8 @@ gfx_convert_func resolve_colorspace(color_space cs, PixelFormat pixelFormat);
const char *pixfmt_to_string(int p);
color_space pixfmt_to_colorspace(int p);
void dump_ffframe(AVFrame *frame, const char *name);
#endif