ffmpeg: new decoder plugin
[mk: fixed indent, changed copyright statement, added autoconf test, fixed includes paths, fixed 2 gcc warnings, don't close input stream twice]
This commit is contained in:
parent
4ee8da2e69
commit
11ad997141
21
configure.ac
21
configure.ac
@ -234,6 +234,12 @@ AC_ARG_ENABLE(wavpack,
|
|||||||
enable_wavpack=$enableval,
|
enable_wavpack=$enableval,
|
||||||
enable_wavpack=yes)
|
enable_wavpack=yes)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ffmpeg,
|
||||||
|
AS_HELP_STRING([--disable-ffmpeg],
|
||||||
|
[enable FFMPEG support (default: enable)]),
|
||||||
|
enable_ffmpeg=$enableval,
|
||||||
|
enable_ffmpeg=yes)
|
||||||
|
|
||||||
AC_ARG_ENABLE(id3,
|
AC_ARG_ENABLE(id3,
|
||||||
AS_HELP_STRING([--disable-id3],
|
AS_HELP_STRING([--disable-id3],
|
||||||
[disable id3 support (default: enable)]),
|
[disable id3 support (default: enable)]),
|
||||||
@ -672,6 +678,14 @@ fi
|
|||||||
|
|
||||||
AM_CONDITIONAL(HAVE_MIKMOD, test x$enable_mod = xyes)
|
AM_CONDITIONAL(HAVE_MIKMOD, test x$enable_mod = xyes)
|
||||||
|
|
||||||
|
if test x$enable_ffmpeg = xyes; then
|
||||||
|
PKG_CHECK_MODULES(FFMPEG, [libavcodec libavformat],
|
||||||
|
AC_DEFINE(HAVE_FFMPEG, 1, [Define for FFMPEG support]),
|
||||||
|
enable_ffmpeg=no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes)
|
||||||
|
|
||||||
case $with_zeroconf in
|
case $with_zeroconf in
|
||||||
no|avahi|bonjour)
|
no|avahi|bonjour)
|
||||||
;;
|
;;
|
||||||
@ -955,6 +969,12 @@ else
|
|||||||
echo " MOD support ...................disabled"
|
echo " MOD support ...................disabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test x$enable_ffmpeg = xyes; then
|
||||||
|
echo " FFMPEG support ................enabled"
|
||||||
|
else
|
||||||
|
echo " FFMPEG support ................disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
if
|
if
|
||||||
test x$enable_mp3 = xno &&
|
test x$enable_mp3 = xno &&
|
||||||
test x$enable_oggvorbis = xno &&
|
test x$enable_oggvorbis = xno &&
|
||||||
@ -964,6 +984,7 @@ if
|
|||||||
test x$enable_aac = xno &&
|
test x$enable_aac = xno &&
|
||||||
test x$enable_mpc = xno &&
|
test x$enable_mpc = xno &&
|
||||||
test x$enable_wavpack = xno &&
|
test x$enable_wavpack = xno &&
|
||||||
|
test x$enable_ffmpeg = xno &&
|
||||||
test x$enable_mod = xno; then
|
test x$enable_mod = xno; then
|
||||||
AC_MSG_ERROR([No input plugins supported!])
|
AC_MSG_ERROR([No input plugins supported!])
|
||||||
fi
|
fi
|
||||||
|
@ -225,6 +225,10 @@ if HAVE_MIKMOD
|
|||||||
mpd_SOURCES += inputPlugins/mod_plugin.c
|
mpd_SOURCES += inputPlugins/mod_plugin.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if HAVE_FFMPEG
|
||||||
|
mpd_SOURCES += inputPlugins/ffmpeg_plugin.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
if HAVE_ZEROCONF
|
if HAVE_ZEROCONF
|
||||||
mpd_SOURCES += zeroconf.c
|
mpd_SOURCES += zeroconf.c
|
||||||
@ -240,6 +244,7 @@ mpd_CPPFLAGS = \
|
|||||||
$(AUDIOFILE_CFLAGS) $(LIBMIKMOD_CFLAGS) \
|
$(AUDIOFILE_CFLAGS) $(LIBMIKMOD_CFLAGS) \
|
||||||
$(ID3TAG_CFLAGS) \
|
$(ID3TAG_CFLAGS) \
|
||||||
$(MAD_CFLAGS) \
|
$(MAD_CFLAGS) \
|
||||||
|
$(FFMPEG_CFLAGS) \
|
||||||
$(GLIB_CFLAGS)
|
$(GLIB_CFLAGS)
|
||||||
mpd_LDADD = $(MPD_LIBS) $(MP4FF_LIB) \
|
mpd_LDADD = $(MPD_LIBS) $(MP4FF_LIB) \
|
||||||
$(AO_LIBS) $(ALSA_LIBS) \
|
$(AO_LIBS) $(ALSA_LIBS) \
|
||||||
@ -248,6 +253,7 @@ mpd_LDADD = $(MPD_LIBS) $(MP4FF_LIB) \
|
|||||||
$(AUDIOFILE_LIBS) $(LIBMIKMOD_LIBS) \
|
$(AUDIOFILE_LIBS) $(LIBMIKMOD_LIBS) \
|
||||||
$(ID3TAG_LIBS) \
|
$(ID3TAG_LIBS) \
|
||||||
$(MAD_LIBS) \
|
$(MAD_LIBS) \
|
||||||
|
$(FFMPEG_LIBS) \
|
||||||
$(GLIB_LIBS)
|
$(GLIB_LIBS)
|
||||||
|
|
||||||
DIST_SUBDIRS = mp4ff
|
DIST_SUBDIRS = mp4ff
|
||||||
|
@ -30,6 +30,7 @@ extern struct decoder_plugin aacPlugin;
|
|||||||
extern struct decoder_plugin mpcPlugin;
|
extern struct decoder_plugin mpcPlugin;
|
||||||
extern struct decoder_plugin wavpackPlugin;
|
extern struct decoder_plugin wavpackPlugin;
|
||||||
extern struct decoder_plugin modPlugin;
|
extern struct decoder_plugin modPlugin;
|
||||||
|
extern struct decoder_plugin ffmpegPlugin;
|
||||||
|
|
||||||
static List *inputPlugin_list;
|
static List *inputPlugin_list;
|
||||||
|
|
||||||
@ -179,6 +180,9 @@ void decoder_plugin_init_all(void)
|
|||||||
#ifdef HAVE_MIKMOD
|
#ifdef HAVE_MIKMOD
|
||||||
decoder_plugin_load(&modPlugin);
|
decoder_plugin_load(&modPlugin);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_FFMPEG
|
||||||
|
decoder_plugin_load(&ffmpegPlugin);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void decoder_plugin_deinit_all(void)
|
void decoder_plugin_deinit_all(void)
|
||||||
|
416
src/inputPlugins/ffmpeg_plugin.c
Normal file
416
src/inputPlugins/ffmpeg_plugin.c
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/* the Music Player Daemon (MPD)
|
||||||
|
* Copyright (C) 2008 Viliam Mateicka <viliam.mateicka@gmail.com>
|
||||||
|
* This project's homepage is: http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../decoder_api.h"
|
||||||
|
#include "../log.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
#include "../log.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <avcodec.h>
|
||||||
|
#include <avformat.h>
|
||||||
|
#include <avio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int audioStream;
|
||||||
|
AVFormatContext *pFormatCtx;
|
||||||
|
AVCodecContext *aCodecCtx;
|
||||||
|
AVCodec *aCodec;
|
||||||
|
struct decoder *decoder;
|
||||||
|
InputStream *input;
|
||||||
|
struct tag *tag;
|
||||||
|
} BasePtrs;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct decoder *decoder;
|
||||||
|
InputStream *input;
|
||||||
|
} FopsHelper;
|
||||||
|
|
||||||
|
int mpdurl_open(URLContext *h, const char *filename, int flags);
|
||||||
|
int mpdurl_read(URLContext *h, unsigned char *buf, int size);
|
||||||
|
int64_t mpdurl_seek(URLContext *h, int64_t pos, int whence);
|
||||||
|
int mpdurl_close(URLContext *h);
|
||||||
|
|
||||||
|
URLProtocol mpdurl_fileops = {
|
||||||
|
.name = "mpd",
|
||||||
|
.url_open = mpdurl_open,
|
||||||
|
.url_read = mpdurl_read,
|
||||||
|
.url_write = NULL,
|
||||||
|
.url_seek = mpdurl_seek,
|
||||||
|
.url_close = mpdurl_close,
|
||||||
|
.next = NULL,
|
||||||
|
.url_read_pause = NULL,
|
||||||
|
.url_read_seek = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int mpdurl_open(URLContext *h, const char *filename, int flags)
|
||||||
|
{
|
||||||
|
uint32_t ptr;
|
||||||
|
FopsHelper *base;
|
||||||
|
if (strlen(filename) == (8+8)) {
|
||||||
|
errno = 0;
|
||||||
|
ptr = (uint32_t) strtoll(filename + 6, NULL, 16);
|
||||||
|
if (errno == 0 && ptr != 0) {
|
||||||
|
base = (FopsHelper *) ptr;
|
||||||
|
h->priv_data = base;
|
||||||
|
h->is_streamed = (base->input->seekable ? 0 : 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FATAL("Invalid format %s:%d\n", filename, flags);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mpdurl_read(URLContext *h, unsigned char *buf, int size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
FopsHelper *base = (FopsHelper *) h->priv_data;
|
||||||
|
while (1) {
|
||||||
|
ret = readFromInputStream(base->input, (void *)buf, size);
|
||||||
|
if (ret == 0) {
|
||||||
|
DEBUG("ret 0\n");
|
||||||
|
if (inputStreamAtEOF(base->input) ||
|
||||||
|
(base->decoder &&
|
||||||
|
decoder_get_command(base->decoder) != DECODE_COMMAND_NONE)) {
|
||||||
|
DEBUG("eof stream\n");
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
my_usleep(10000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t mpdurl_seek(URLContext *h, int64_t pos, int whence)
|
||||||
|
{
|
||||||
|
FopsHelper *base = (FopsHelper *) h->priv_data;
|
||||||
|
if (whence != AVSEEK_SIZE) { //only ftell
|
||||||
|
(void) seekInputStream(base->input, pos, whence);
|
||||||
|
}
|
||||||
|
return base->input->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mpdurl_close(URLContext *h)
|
||||||
|
{
|
||||||
|
FopsHelper *base = (FopsHelper *) h->priv_data;
|
||||||
|
if (base && base->input->seekable) {
|
||||||
|
(void) seekInputStream(base->input, 0, SEEK_SET);
|
||||||
|
}
|
||||||
|
h->priv_data = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffmpeg_init(void)
|
||||||
|
{
|
||||||
|
av_register_all();
|
||||||
|
register_protocol(&mpdurl_fileops);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffmpeg_helper(InputStream *input, int (*callback)(BasePtrs *ptrs),
|
||||||
|
BasePtrs *ptrs)
|
||||||
|
{
|
||||||
|
AVFormatContext *pFormatCtx;
|
||||||
|
AVCodecContext *aCodecCtx;
|
||||||
|
AVCodec *aCodec;
|
||||||
|
int ret, audioStream;
|
||||||
|
unsigned i;
|
||||||
|
FopsHelper fopshelp;
|
||||||
|
char url[24];
|
||||||
|
|
||||||
|
fopshelp.input = input;
|
||||||
|
if (ptrs && ptrs->decoder) {
|
||||||
|
fopshelp.decoder = ptrs->decoder; //are we in decoding loop ?
|
||||||
|
} else {
|
||||||
|
fopshelp.decoder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ffmpeg works with ours "fileops" helper
|
||||||
|
sprintf(url, "mpd://0x%8x", (unsigned int) &fopshelp);
|
||||||
|
|
||||||
|
if (av_open_input_file(&pFormatCtx, url, NULL, 0, NULL)!=0) {
|
||||||
|
ERROR("Open failed!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (av_find_stream_info(pFormatCtx)<0) {
|
||||||
|
ERROR("Couldn't find stream info!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioStream = -1;
|
||||||
|
for(i=0; i<pFormatCtx->nb_streams; i++) {
|
||||||
|
if (pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO &&
|
||||||
|
audioStream < 0) {
|
||||||
|
audioStream=i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(audioStream==-1) {
|
||||||
|
ERROR("No audio stream inside!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
aCodecCtx = pFormatCtx->streams[audioStream]->codec;
|
||||||
|
aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
|
||||||
|
|
||||||
|
if (!aCodec) {
|
||||||
|
ERROR("Unsupported audio codec!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avcodec_open(aCodecCtx, aCodec)<0) {
|
||||||
|
ERROR("Could not open codec!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
ptrs->audioStream = audioStream;
|
||||||
|
ptrs->pFormatCtx = pFormatCtx;
|
||||||
|
ptrs->aCodecCtx = aCodecCtx;
|
||||||
|
ptrs->aCodec = aCodec;
|
||||||
|
|
||||||
|
ret = (*callback)( ptrs );
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
DEBUG("playable\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
avcodec_close(aCodecCtx);
|
||||||
|
av_close_input_file(pFormatCtx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ffmpeg_try_decode(InputStream *input)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (input->seekable) {
|
||||||
|
ret = ffmpeg_helper(input, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
return (ret == -1 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffmpeg_decode_internal(BasePtrs *base)
|
||||||
|
{
|
||||||
|
struct decoder *decoder = base->decoder;
|
||||||
|
AVCodecContext *aCodecCtx = base->aCodecCtx;
|
||||||
|
AVFormatContext *pFormatCtx = base->pFormatCtx;
|
||||||
|
AVPacket packet;
|
||||||
|
int len, audio_size;
|
||||||
|
int position;
|
||||||
|
struct audio_format audio_format;
|
||||||
|
int current, total_time;
|
||||||
|
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||||
|
|
||||||
|
total_time = 0;
|
||||||
|
|
||||||
|
DEBUG("decoder_start\n");
|
||||||
|
|
||||||
|
if (aCodecCtx->channels > 2) {
|
||||||
|
aCodecCtx->channels = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_format.bits = (uint8_t)16;
|
||||||
|
audio_format.sample_rate = (unsigned int)aCodecCtx->sample_rate;
|
||||||
|
audio_format.channels = aCodecCtx->channels;
|
||||||
|
|
||||||
|
// frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK);
|
||||||
|
// total_time = ((float)frame_count / (float)audio_format.sample_rate);
|
||||||
|
|
||||||
|
//there is some problem with this on some demux (mp3 at least)
|
||||||
|
if (pFormatCtx->duration != (int)AV_NOPTS_VALUE) {
|
||||||
|
total_time = pFormatCtx->duration / AV_TIME_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("ffmpeg sample rate: %dHz %d channels\n",
|
||||||
|
aCodecCtx->sample_rate, aCodecCtx->channels);
|
||||||
|
|
||||||
|
decoder_initialized(decoder, &audio_format, total_time);
|
||||||
|
|
||||||
|
position = 0;
|
||||||
|
|
||||||
|
DEBUG("duration:%d (%d secs)\n", (int) pFormatCtx->duration,
|
||||||
|
(int) total_time);
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
|
||||||
|
|
||||||
|
DEBUG("seek\n");
|
||||||
|
decoder_clear(decoder);
|
||||||
|
current = decoder_seek_where(decoder) * AV_TIME_BASE;
|
||||||
|
|
||||||
|
if (av_seek_frame(pFormatCtx, -1, current , 0) < 0) {
|
||||||
|
WARNING("seek to %d failed\n", current);
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder_command_finished(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (av_read_frame(pFormatCtx, &packet) >= 0) {
|
||||||
|
if(packet.stream_index == base->audioStream) {
|
||||||
|
|
||||||
|
position = av_rescale_q(packet.pts, pFormatCtx->streams[base->audioStream]->time_base,
|
||||||
|
(AVRational){1, 1});
|
||||||
|
|
||||||
|
audio_size = sizeof(audio_buf);
|
||||||
|
len = avcodec_decode_audio2(aCodecCtx,
|
||||||
|
(int16_t *)audio_buf,
|
||||||
|
&audio_size,
|
||||||
|
packet.data,
|
||||||
|
packet.size);
|
||||||
|
|
||||||
|
if(len >= 0) {
|
||||||
|
if(audio_size >= 0) {
|
||||||
|
// DEBUG("sending data %d/%d\n", audio_size, len);
|
||||||
|
|
||||||
|
decoder_data(decoder, NULL, 1,
|
||||||
|
audio_buf, audio_size,
|
||||||
|
position, //(float)current / (float)audio_format.sample_rate,
|
||||||
|
aCodecCtx->bit_rate / 1000, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARNING("skiping frame!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_free_packet(&packet);
|
||||||
|
} else {
|
||||||
|
//end of file
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (decoder_get_command(decoder) != DECODE_COMMAND_STOP);
|
||||||
|
|
||||||
|
decoder_flush(decoder);
|
||||||
|
|
||||||
|
DEBUG("decoder finish\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffmpeg_decode(struct decoder *decoder, InputStream *input)
|
||||||
|
{
|
||||||
|
BasePtrs base;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DEBUG("decode start\n");
|
||||||
|
|
||||||
|
base.input = input;
|
||||||
|
base.decoder = decoder;
|
||||||
|
|
||||||
|
ret = ffmpeg_helper(input, ffmpeg_decode_internal, &base);
|
||||||
|
|
||||||
|
DEBUG("decode finish\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ffmpeg_tag_internal(BasePtrs *base)
|
||||||
|
{
|
||||||
|
struct tag *tag = (struct tag *) base->tag;
|
||||||
|
|
||||||
|
if (base->pFormatCtx->duration != (int)AV_NOPTS_VALUE) {
|
||||||
|
tag->time = base->pFormatCtx->duration / AV_TIME_BASE;
|
||||||
|
} else {
|
||||||
|
tag->time = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//no tag reading in ffmpeg, check if playable
|
||||||
|
static struct tag *ffmpeg_tag(char *file)
|
||||||
|
{
|
||||||
|
InputStream input;
|
||||||
|
BasePtrs base;
|
||||||
|
int ret;
|
||||||
|
struct tag *tag = NULL;
|
||||||
|
|
||||||
|
if (openInputStream(&input, file) < 0) {
|
||||||
|
ERROR("failed to open %s\n", file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = tag_new();
|
||||||
|
|
||||||
|
base.tag = tag;
|
||||||
|
ret = ffmpeg_helper(&input, ffmpeg_tag_internal, &base);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
free(tag);
|
||||||
|
tag = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeInputStream(&input);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ffmpeg can decode almost everything from open codecs
|
||||||
|
* and also some of propietary codecs
|
||||||
|
* its hard to tell what can ffmpeg decode
|
||||||
|
* we can later put this into configure script
|
||||||
|
* to be sure ffmpeg is used to handle
|
||||||
|
* only that files
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *ffmpeg_Suffixes[] = {
|
||||||
|
"wma", "asf", "wmv", "mpeg", "mpg", "avi", "vob", "mov", "qt", "swf", "rm", "swf",
|
||||||
|
"mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
//not sure if this is correct...
|
||||||
|
static const char *ffmpeg_Mimetypes[] = {
|
||||||
|
"video/x-ms-asf",
|
||||||
|
"audio/x-ms-wma",
|
||||||
|
"audio/x-ms-wax",
|
||||||
|
"video/x-ms-wmv",
|
||||||
|
"video/x-ms-wvx",
|
||||||
|
"video/x-ms-wm",
|
||||||
|
"video/x-ms-wmx",
|
||||||
|
"application/x-ms-wmz",
|
||||||
|
"application/x-ms-wmd",
|
||||||
|
"audio/mpeg",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct decoder_plugin ffmpegPlugin = {
|
||||||
|
.name = "ffmpeg",
|
||||||
|
.init = ffmpeg_init,
|
||||||
|
.try_decode = ffmpeg_try_decode,
|
||||||
|
.stream_decode = ffmpeg_decode,
|
||||||
|
.tag_dup = ffmpeg_tag,
|
||||||
|
.stream_types = INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
|
||||||
|
.suffixes = ffmpeg_Suffixes,
|
||||||
|
.mime_types = ffmpeg_Mimetypes
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user