/*
* DEMUXER v2.5
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "options.h"
#include "talloc.h"
#include "mp_msg.h"
#include "m_config.h"
#include "libvo/fastmemcpy.h"
#include "stream/stream.h"
#include "demuxer.h"
#include "stheader.h"
#include "mf.h"
#include "libaf/format.h"
#include "libavcodec/avcodec.h"
#if MP_INPUT_BUFFER_PADDING_SIZE < FF_INPUT_BUFFER_PADDING_SIZE
#error MP_INPUT_BUFFER_PADDING_SIZE is too small!
#endif
static void clear_parser(sh_common_t *sh);
// Demuxer list
extern const struct demuxer_desc demuxer_desc_edl;
extern const struct demuxer_desc demuxer_desc_cue;
extern const demuxer_desc_t demuxer_desc_rawaudio;
extern const demuxer_desc_t demuxer_desc_rawvideo;
extern const demuxer_desc_t demuxer_desc_tv;
extern const demuxer_desc_t demuxer_desc_mf;
extern const demuxer_desc_t demuxer_desc_avi;
extern const demuxer_desc_t demuxer_desc_asf;
extern const demuxer_desc_t demuxer_desc_matroska;
extern const demuxer_desc_t demuxer_desc_gif;
extern const demuxer_desc_t demuxer_desc_lavf;
extern const demuxer_desc_t demuxer_desc_lavf_preferred;
extern const demuxer_desc_t demuxer_desc_mng;
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
* libraries and demuxers requiring binary support. */
const demuxer_desc_t *const demuxer_list[] = {
&demuxer_desc_edl,
&demuxer_desc_cue,
&demuxer_desc_rawaudio,
&demuxer_desc_rawvideo,
#ifdef CONFIG_TV
&demuxer_desc_tv,
#endif
&demuxer_desc_mf,
&demuxer_desc_lavf_preferred,
&demuxer_desc_avi,
&demuxer_desc_asf,
&demuxer_desc_matroska,
#ifdef CONFIG_GIF
&demuxer_desc_gif,
#endif
&demuxer_desc_lavf,
#ifdef CONFIG_MNG
&demuxer_desc_mng,
#endif
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
* libraries and demuxers requiring binary support. */
NULL
};
static struct demux_packet *create_packet(size_t len)
{
if (len > 1000000000) {
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Attempt to allocate demux packet "
"over 1 GB!\n");
abort();
}
struct demux_packet *dp = malloc(sizeof(struct demux_packet));
dp->len = len;
dp->next = NULL;
dp->pts = MP_NOPTS_VALUE;
dp->duration = -1;
dp->stream_pts = MP_NOPTS_VALUE;
dp->pos = 0;
dp->keyframe = false;
dp->refcount = 1;
dp->master = NULL;
dp->buffer = NULL;
dp->avpacket = NULL;
return dp;
}
struct demux_packet *new_demux_packet(size_t len)
{
struct demux_packet *dp = create_packet(len);
dp->buffer = malloc(len + MP_INPUT_BUFFER_PADDING_SIZE);
if (!dp->buffer) {
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
memset(dp->buffer + len, 0, 8);
return dp;
}
// data must already have suitable padding
struct demux_packet *new_demux_packet_fromdata(void *data, size_t len)
{
struct demux_packet *dp = create_packet(len);
dp->buffer = data;
return dp;
}
void resize_demux_packet(struct demux_packet *dp, size_t len)
{
if (len > 1000000000) {
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Attempt to realloc demux packet "
"over 1 GB!\n");
abort();
}
dp->buffer = realloc(dp->buffer, len + MP_INPUT_BUFFER_PADDING_SIZE);
if (!dp->buffer) {
mp_msg(MSGT_DEMUXER, MSGL_FATAL, "Memory allocation failure!\n");
abort();
}
memset(dp->buffer + len, 0, 8);
dp->len = len;
}
struct demux_packet *clone_demux_packet(struct demux_packet *pack)
{
struct demux_packet *dp = malloc(sizeof(struct demux_packet));
while (pack->master)
pack = pack->master; // find the master
memcpy(dp, pack, sizeof(struct demux_packet));
dp->next = NULL;
dp->refcount = 0;
dp->master = pack;
pack->refcount++;
return dp;
}
void free_demux_packet(struct demux_packet *dp)
{
if (dp->master == NULL) { //dp is a master packet
dp->refcount--;
if (dp->refcount == 0) {
if (dp->avpacket)
talloc_free(dp->avpacket);
else
free(dp->buffer);
free(dp);
}
return;
}
// dp is a clone:
free_demux_packet(dp->master);
free(dp);
}
static void free_demuxer_stream(struct demux_stream *ds)
{
ds_free_packs(ds);
free(ds);
}
static struct demux_stream *new_demuxer_stream(struct demuxer *demuxer,
enum stream_type type, int id)
{
demux_stream_t *ds = malloc(sizeof(demux_stream_t));
*ds = (demux_stream_t) {
.stream_type = type,
.id = id,
.demuxer = demuxer,
.asf_seq = -1,
};
return ds;
}
struct sh_stream *ds_gsh(struct demux_stream *ds)
{
// Ideally ds would have a gsh field, but since all the old demuxers set
// ds->sh themselves and we don't want to change them, enjoy this hack.
if (!ds->sh)
return NULL;
switch (ds->stream_type) {
case STREAM_VIDEO: return ((struct sh_video *)ds->sh)->gsh;
case STREAM_AUDIO: return ((struct sh_audio *)ds->sh)->gsh;
case STREAM_SUB: return ((struct sh_sub *)ds->sh)->gsh;
}
assert(false);
}
/**
* Get demuxer description structure for a given demuxer type
*
* @param file_format type of the demuxer
* @return structure for the demuxer, NULL if not found
*/
static const demuxer_desc_t *get_demuxer_desc_from_type(int file_format)
{
int i;
for (i = 0; demuxer_list[i]; i++)
if (file_format == demuxer_list[i]->type)
return demuxer_list[i];
return NULL;
}
demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
int a_id, int v_id, int s_id, char *filename)
{
struct demuxer *d = talloc_zero(NULL, struct demuxer);
d->stream = stream;
d->stream_pts = MP_NOPTS_VALUE;
d->reference_clock = MP_NOPTS_VALUE;
d->movi_start = stream->start_pos;
d->movi_end = stream->end_pos;
d->seekable = 1;
d->synced = 0;
d->filepos = -1;
d->audio = new_demuxer_stream(d, STREAM_VIDEO, a_id);
d->video = new_demuxer_stream(d, STREAM_AUDIO, v_id);
d->sub = new_demuxer_stream(d, STREAM_SUB, s_id);
d->ds[STREAM_VIDEO] = d->video;
d->ds[STREAM_AUDIO] = d->audio;
d->ds[STREAM_SUB] = d->sub;
d->type = type;
d->opts = opts;
if (type)
if (!(d->desc = get_demuxer_desc_from_type(type)))
mp_msg(MSGT_DEMUXER, MSGL_ERR,
"BUG! Invalid demuxer type in new_demuxer(), "
"big troubles ahead.");
if (filename) // Filename hack for avs_check_file
d->filename = strdup(filename);
stream_seek(stream, stream->start_pos);
return d;
}
const char *sh_sub_type2str(int type)
{
switch (type) {
case 't': return "text";
case 'm': return "movtext";
case 'a': return "ass";
case 'v': return "vobsub";
case 'x': return "xsub";
case 'b': return "dvb";
case 'd': return "dvb-teletext";
case 'p': return "hdmv pgs";
}
return "
|