diff options
Diffstat (limited to 'libmpdemux/demux_lavf.c')
-rw-r--r-- | libmpdemux/demux_lavf.c | 1092 |
1 files changed, 0 insertions, 1092 deletions
diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c deleted file mode 100644 index 35f3f6a83e..0000000000 --- a/libmpdemux/demux_lavf.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at> - * - * 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 <unistd.h> -#include <limits.h> -#include <stdbool.h> -#include <string.h> -#include <assert.h> - -#include <libavformat/avformat.h> -#include <libavformat/avio.h> -#include <libavutil/avutil.h> -#include <libavutil/avstring.h> -#include <libavutil/mathematics.h> -#include <libavutil/opt.h> -#include "libav_compat.h" - -#include "config.h" -#include "options.h" -#include "mp_msg.h" -#include "av_opts.h" -#include "bstr.h" - -#include "stream/stream.h" -#include "aviprint.h" -#include "demuxer.h" -#include "stheader.h" -#include "m_option.h" - -#include "mp_taglists.h" - -#define INITIAL_PROBE_SIZE STREAM_BUFFER_SIZE -#define SMALL_MAX_PROBE_SIZE (32 * 1024) -#define PROBE_BUF_SIZE (2 * 1024 * 1024) - -const m_option_t lavfdopts_conf[] = { - OPT_INTRANGE("probesize", lavfdopts.probesize, 0, 32, INT_MAX), - OPT_STRING("format", lavfdopts.format, 0), - OPT_INTRANGE("analyzeduration", lavfdopts.analyzeduration, 0, 0, INT_MAX), - OPT_STRING("cryptokey", lavfdopts.cryptokey, 0), - OPT_STRING("o", lavfdopts.avopt, 0), - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - -#define BIO_BUFFER_SIZE 32768 - -typedef struct lavf_priv { - AVInputFormat *avif; - AVFormatContext *avfc; - AVIOContext *pb; - uint8_t buffer[BIO_BUFFER_SIZE]; - int audio_streams; - int video_streams; - int sub_streams; - int autoselect_sub; - int64_t last_pts; - int astreams[MAX_A_STREAMS]; - int vstreams[MAX_V_STREAMS]; - int sstreams[MAX_S_STREAMS]; - int cur_program; - int nb_streams_last; - bool internet_radio_hack; - bool use_dts; - bool seek_by_bytes; - int bitrate; -} lavf_priv_t; - -static int mp_read(void *opaque, uint8_t *buf, int size) -{ - struct demuxer *demuxer = opaque; - struct stream *stream = demuxer->stream; - int ret; - - ret = stream_read(stream, buf, size); - - mp_msg(MSGT_HEADER, MSGL_DBG2, - "%d=mp_read(%p, %p, %d), pos: %"PRId64", eof:%d\n", - ret, stream, buf, size, stream_tell(stream), stream->eof); - return ret; -} - -static int64_t mp_seek(void *opaque, int64_t pos, int whence) -{ - struct demuxer *demuxer = opaque; - struct stream *stream = demuxer->stream; - int64_t current_pos; - mp_msg(MSGT_HEADER, MSGL_DBG2, "mp_seek(%p, %"PRId64", %d)\n", - stream, pos, whence); - if (whence == SEEK_CUR) - pos += stream_tell(stream); - else if (whence == SEEK_END && stream->end_pos > 0) - pos += stream->end_pos; - else if (whence == SEEK_SET) - pos += stream->start_pos; - else if (whence == AVSEEK_SIZE && stream->end_pos > 0) { - off_t size; - if (stream_control(stream, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) - return size; - return stream->end_pos - stream->start_pos; - } else - return -1; - - if (pos < 0) - return -1; - current_pos = stream_tell(stream); - if (stream_seek(stream, pos) == 0) { - stream_reset(stream); - stream_seek(stream, current_pos); - return -1; - } - - return pos - stream->start_pos; -} - -static int64_t mp_read_seek(void *opaque, int stream_idx, int64_t ts, int flags) -{ - struct demuxer *demuxer = opaque; - struct stream *stream = demuxer->stream; - struct lavf_priv *priv = demuxer->priv; - - AVStream *st = priv->avfc->streams[stream_idx]; - double pts = (double)ts * st->time_base.num / st->time_base.den; - int ret = stream_control(stream, STREAM_CTRL_SEEK_TO_TIME, &pts); - if (ret < 0) - ret = AVERROR(ENOSYS); - return ret; -} - -static void list_formats(void) -{ - mp_msg(MSGT_DEMUX, MSGL_INFO, "Available lavf input formats:\n"); - AVInputFormat *fmt = NULL; - while ((fmt = av_iformat_next(fmt))) - mp_msg(MSGT_DEMUX, MSGL_INFO, "%15s : %s\n", fmt->name, fmt->long_name); -} - -static int lavf_check_file(demuxer_t *demuxer) -{ - struct MPOpts *opts = demuxer->opts; - struct lavfdopts *lavfdopts = &opts->lavfdopts; - AVProbeData avpd; - lavf_priv_t *priv; - int probe_data_size = 0; - int read_size = INITIAL_PROBE_SIZE; - int score; - - if (!demuxer->priv) - demuxer->priv = calloc(sizeof(lavf_priv_t), 1); - priv = demuxer->priv; - priv->autoselect_sub = -1; - - char *format = lavfdopts->format; - if (!format) - format = demuxer->stream->lavf_type; - if (format) { - if (strcmp(format, "help") == 0) { - list_formats(); - return 0; - } - priv->avif = av_find_input_format(format); - if (!priv->avif) { - mp_msg(MSGT_DEMUX, MSGL_FATAL, "Unknown lavf format %s\n", format); - return 0; - } - mp_msg(MSGT_DEMUX, MSGL_INFO, "Forced lavf %s demuxer\n", - priv->avif->long_name); - return DEMUXER_TYPE_LAVF; - } - - avpd.buf = av_mallocz(FFMAX(BIO_BUFFER_SIZE, PROBE_BUF_SIZE) + - FF_INPUT_BUFFER_PADDING_SIZE); - do { - read_size = stream_read(demuxer->stream, avpd.buf + probe_data_size, - read_size); - if (read_size < 0) { - av_free(avpd.buf); - return 0; - } - probe_data_size += read_size; - avpd.filename = demuxer->stream->url; - if (!avpd.filename) { - mp_msg(MSGT_DEMUX, MSGL_WARN, "Stream url is not set!\n"); - avpd.filename = ""; - } - if (!strncmp(avpd.filename, "ffmpeg://", 9) || - !strncmp(avpd.filename, "lavf://", 7)) - avpd.filename += 9; - avpd.buf_size = probe_data_size; - - score = 0; - priv->avif = av_probe_input_format2(&avpd, probe_data_size > 0, &score); - read_size = FFMIN(2 * read_size, PROBE_BUF_SIZE - probe_data_size); - } while ((demuxer->desc->type != DEMUXER_TYPE_LAVF_PREFERRED || - probe_data_size < SMALL_MAX_PROBE_SIZE) && - score <= AVPROBE_SCORE_MAX / 4 && - read_size > 0 && probe_data_size < PROBE_BUF_SIZE); - av_free(avpd.buf); - - if (!priv->avif || score <= AVPROBE_SCORE_MAX / 4) { - mp_msg(MSGT_HEADER, MSGL_V, - "LAVF_check: no clue about this gibberish!\n"); - return 0; - } else - mp_msg(MSGT_HEADER, MSGL_V, "LAVF_check: %s\n", priv->avif->long_name); - - demuxer->filetype = priv->avif->long_name; - if (!demuxer->filetype) - demuxer->filetype = priv->avif->name; - - return DEMUXER_TYPE_LAVF; -} - -static bool matches_avinputformat_name(struct lavf_priv *priv, - const char *name) -{ - const char *avifname = priv->avif->name; - while (1) { - const char *next = strchr(avifname, ','); - if (!next) - return !strcmp(avifname, name); - int len = next - avifname; - if (len == strlen(name) && !memcmp(avifname, name, len)) - return true; - avifname = next + 1; - } -} - -/* formats for which an internal demuxer is preferred */ -static const char * const preferred_internal[] = { - /* lavf Matroska demuxer doesn't support ordered chapters and fails - * for more files */ - "matroska", - NULL -}; - -static int lavf_check_preferred_file(demuxer_t *demuxer) -{ - if (lavf_check_file(demuxer)) { - const char * const *p; - lavf_priv_t *priv = demuxer->priv; - for (p = preferred_internal; *p; p++) - if (matches_avinputformat_name(priv, *p)) - return 0; - return DEMUXER_TYPE_LAVF_PREFERRED; - } - return 0; -} - -static uint8_t char2int(char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - return 0; -} - -static void parse_cryptokey(AVFormatContext *avfc, const char *str) -{ - int len = strlen(str) / 2; - uint8_t *key = av_mallocz(len); - int i; - avfc->keylen = len; - avfc->key = key; - for (i = 0; i < len; i++, str += 2) - *key++ = (char2int(str[0]) << 4) | char2int(str[1]); -} - -static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) -{ - lavf_priv_t *priv = demuxer->priv; - AVStream *st = avfc->streams[i]; - AVCodecContext *codec = st->codec; - char *stream_type = NULL; - int stream_id; - AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); - AVDictionaryEntry *title = av_dict_get(st->metadata, "title", NULL, 0); - // Work around collisions resulting from the hacks changing codec_tag. - int lavf_codec_tag = codec->codec_tag; - // Don't use native MPEG codec tag values with our generic tag tables. - // May contain for example value 3 for MP3, which we'd map to PCM audio. - if (matches_avinputformat_name(priv, "mpeg") || - matches_avinputformat_name(priv, "mpegts")) - codec->codec_tag = 0; - int override_tag = mp_taglist_override(codec->codec_id); - // For some formats (like PCM) always trust CODEC_ID_* more than codec_tag - if (override_tag) - codec->codec_tag = override_tag; - - AVCodec *avc = avcodec_find_decoder(codec->codec_id); - const char *codec_name = avc ? avc->name : "unknown"; - - bool set_demuxer_id = matches_avinputformat_name(priv, "mpeg"); - - switch (codec->codec_type) { - case AVMEDIA_TYPE_AUDIO: { - WAVEFORMATEX *wf; - sh_audio_t *sh_audio; - sh_audio = new_sh_audio_aid(demuxer, i, priv->audio_streams); - if (!sh_audio) - break; - sh_audio->demuxer_codecname = codec_name; - if (set_demuxer_id) - sh_audio->gsh->demuxer_id = st->id; - stream_type = "audio"; - priv->astreams[priv->audio_streams] = i; - sh_audio->libav_codec_id = codec->codec_id; - sh_audio->gsh->lavf_codec_tag = lavf_codec_tag; - wf = calloc(sizeof(*wf) + codec->extradata_size, 1); - // mp4a tag is used for all mp4 files no matter what they actually contain - if (codec->codec_tag == MKTAG('m', 'p', '4', 'a')) - codec->codec_tag = 0; - if (!codec->codec_tag) - codec->codec_tag = mp_taglist_audio(codec->codec_id); - if (!codec->codec_tag) - codec->codec_tag = -1; - wf->wFormatTag = codec->codec_tag; - wf->nChannels = codec->channels; - wf->nSamplesPerSec = codec->sample_rate; - wf->nAvgBytesPerSec = codec->bit_rate / 8; - wf->nBlockAlign = codec->block_align; - wf->wBitsPerSample = codec->bits_per_coded_sample; - wf->cbSize = codec->extradata_size; - if (codec->extradata_size) - memcpy(wf + 1, codec->extradata, codec->extradata_size); - sh_audio->wf = wf; - sh_audio->audio.dwSampleSize = codec->block_align; - if (codec->frame_size && codec->sample_rate) { - sh_audio->audio.dwScale = codec->frame_size; - sh_audio->audio.dwRate = codec->sample_rate; - } else { - sh_audio->audio.dwScale = codec->block_align ? codec->block_align * 8 : 8; - sh_audio->audio.dwRate = codec->bit_rate; - } - int g = av_gcd(sh_audio->audio.dwScale, sh_audio->audio.dwRate); - sh_audio->audio.dwScale /= g; - sh_audio->audio.dwRate /= g; -// printf("sca:%d rat:%d fs:%d sr:%d ba:%d\n", sh_audio->audio.dwScale, sh_audio->audio.dwRate, codec->frame_size, codec->sample_rate, codec->block_align); - sh_audio->ds = demuxer->audio; - sh_audio->format = codec->codec_tag; - sh_audio->channels = codec->channels; - sh_audio->samplerate = codec->sample_rate; - sh_audio->i_bps = codec->bit_rate / 8; - switch (codec->codec_id) { - case CODEC_ID_PCM_S8: - case CODEC_ID_PCM_U8: - sh_audio->samplesize = 1; - break; - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_U16BE: - sh_audio->samplesize = 2; - break; - case CODEC_ID_PCM_ALAW: - sh_audio->format = 0x6; - break; - case CODEC_ID_PCM_MULAW: - sh_audio->format = 0x7; - break; - } - if (title && title->value) { - sh_audio->gsh->title = talloc_strdup(sh_audio, title->value); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_NAME=%s\n", - priv->audio_streams, title->value); - } - if (lang && lang->value) { - sh_audio->lang = talloc_strdup(sh_audio, lang->value); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", - priv->audio_streams, sh_audio->lang); - } - if (st->disposition & AV_DISPOSITION_DEFAULT) - sh_audio->gsh->default_track = 1; - if (mp_msg_test(MSGT_HEADER, MSGL_V)) - print_wave_header(sh_audio->wf, MSGL_V); - st->discard = AVDISCARD_ALL; - stream_id = priv->audio_streams++; - break; - } - case AVMEDIA_TYPE_VIDEO: { - sh_video_t *sh_video; - BITMAPINFOHEADER *bih; - sh_video = new_sh_video_vid(demuxer, i, priv->video_streams); - if (!sh_video) - break; - sh_video->demuxer_codecname = codec_name; - if (set_demuxer_id) - sh_video->gsh->demuxer_id = st->id; - stream_type = "video"; - priv->vstreams[priv->video_streams] = i; - sh_video->libav_codec_id = codec->codec_id; - sh_video->gsh->lavf_codec_tag = lavf_codec_tag; - bih = calloc(sizeof(*bih) + codec->extradata_size, 1); - - if (codec->codec_id == CODEC_ID_RAWVIDEO) { - switch (codec->pix_fmt) { - case PIX_FMT_RGB24: - codec->codec_tag = MKTAG(24, 'B', 'G', 'R'); - case PIX_FMT_BGR24: - codec->codec_tag = MKTAG(24, 'R', 'G', 'B'); - } - if (!codec->codec_tag) - codec->codec_tag = avcodec_pix_fmt_to_codec_tag(codec->pix_fmt); - } else if (!codec->codec_tag) { - codec->codec_tag = mp_taglist_video(codec->codec_id); - /* 0 might mean either unset or rawvideo; if codec_id - * was not RAWVIDEO assume it's unset - */ - if (!codec->codec_tag) - codec->codec_tag = -1; - } - bih->biSize = sizeof(*bih) + codec->extradata_size; - bih->biWidth = codec->width; - bih->biHeight = codec->height; - bih->biBitCount = codec->bits_per_coded_sample; - bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8; - bih->biCompression = codec->codec_tag; - sh_video->bih = bih; - sh_video->disp_w = codec->width; - sh_video->disp_h = codec->height; - if (st->time_base.den) { /* if container has time_base, use that */ - sh_video->video.dwRate = st->time_base.den; - sh_video->video.dwScale = st->time_base.num; - } else { - sh_video->video.dwRate = codec->time_base.den; - sh_video->video.dwScale = codec->time_base.num; - } - /* Try to make up some frame rate value, even if it's not reliable. - * FPS information is needed to support subtitle formats which base - * timing on frame numbers. - * Libavformat seems to report no "reliable" FPS value for AVI files, - * while they are typically constant enough FPS that the value this - * heuristic makes up works with subtitles in practice. - */ - double fps; - if (st->r_frame_rate.num) - fps = av_q2d(st->r_frame_rate); - else - fps = 1.0 / FFMAX(av_q2d(st->time_base), - av_q2d(st->codec->time_base) * - st->codec->ticks_per_frame); - sh_video->fps = fps; - sh_video->frametime = 1 / fps; - sh_video->format = bih->biCompression; - if (st->sample_aspect_ratio.num) - sh_video->aspect = codec->width * st->sample_aspect_ratio.num - / (float)(codec->height * st->sample_aspect_ratio.den); - else - sh_video->aspect = codec->width * codec->sample_aspect_ratio.num - / (float)(codec->height * codec->sample_aspect_ratio.den); - sh_video->i_bps = codec->bit_rate / 8; - if (title && title->value) { - sh_video->gsh->title = talloc_strdup(sh_video, title->value); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VID_%d_NAME=%s\n", - priv->video_streams, title->value); - } - mp_msg(MSGT_DEMUX, MSGL_DBG2, "aspect= %d*%d/(%d*%d)\n", - codec->width, codec->sample_aspect_ratio.num, - codec->height, codec->sample_aspect_ratio.den); - - sh_video->ds = demuxer->video; - if (codec->extradata_size) - memcpy(sh_video->bih + 1, codec->extradata, codec->extradata_size); - if ( mp_msg_test(MSGT_HEADER, MSGL_V)) - print_video_header(sh_video->bih, MSGL_V); - if (demuxer->video->id != priv->video_streams - && demuxer->video->id != -1) - st->discard = AVDISCARD_ALL; - else { - demuxer->video->id = i; - demuxer->video->sh = demuxer->v_streams[i]; - } - stream_id = priv->video_streams++; - break; - } - case AVMEDIA_TYPE_SUBTITLE: { - sh_sub_t *sh_sub; - char type; - if (codec->codec_id == CODEC_ID_TEXT || - codec->codec_id == AV_CODEC_ID_SUBRIP) - type = 't'; - else if (codec->codec_id == CODEC_ID_MOV_TEXT) - type = 'm'; - else if (codec->codec_id == CODEC_ID_SSA) - type = 'a'; - else if (codec->codec_id == CODEC_ID_DVD_SUBTITLE) - type = 'v'; - else if (codec->codec_id == CODEC_ID_XSUB) - type = 'x'; - else if (codec->codec_id == CODEC_ID_DVB_SUBTITLE) - type = 'b'; - else if (codec->codec_id == CODEC_ID_DVB_TELETEXT) - type = 'd'; - else if (codec->codec_id == CODEC_ID_HDMV_PGS_SUBTITLE) - type = 'p'; - else - break; - sh_sub = new_sh_sub_sid(demuxer, i, priv->sub_streams); - if (!sh_sub) - break; - sh_sub->demuxer_codecname = codec_name; - if (set_demuxer_id) - sh_sub->gsh->demuxer_id = st->id; - stream_type = "subtitle"; - priv->sstreams[priv->sub_streams] = i; - sh_sub->libav_codec_id = codec->codec_id; - sh_sub->gsh->lavf_codec_tag = lavf_codec_tag; - sh_sub->type = type; - if (codec->extradata_size) { - sh_sub->extradata = malloc(codec->extradata_size); - memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size); - sh_sub->extradata_len = codec->extradata_size; - } - if (title && title->value) { - sh_sub->gsh->title = talloc_strdup(sh_sub, title->value); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_NAME=%s\n", - priv->sub_streams, title->value); - } - if (lang && lang->value) { - sh_sub->lang = talloc_strdup(sh_sub, lang->value); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", - priv->sub_streams, sh_sub->lang); - } - if (st->disposition & AV_DISPOSITION_DEFAULT) - sh_sub->gsh->default_track = 1; - stream_id = priv->sub_streams++; - break; - } - case AVMEDIA_TYPE_ATTACHMENT: { - AVDictionaryEntry *ftag = av_dict_get(st->metadata, "filename", - NULL, 0); - char *filename = ftag ? ftag->value : NULL; - if (st->codec->codec_id == CODEC_ID_TTF) - demuxer_add_attachment(demuxer, bstr0(filename), - bstr0("application/x-truetype-font"), - (struct bstr){codec->extradata, - codec->extradata_size}); - break; - } - default: - st->discard = AVDISCARD_ALL; - } - if (stream_type) { - if (!avc && *stream_type == 's' && demuxer->s_streams[i]) - codec_name = sh_sub_type2str((demuxer->s_streams[i])->type); - mp_msg(MSGT_DEMUX, MSGL_V, "[lavf] stream %d: %s (%s), -%cid %d", - i, stream_type, codec_name, *stream_type, stream_id); - if (lang && lang->value && *stream_type != 'v') - mp_msg(MSGT_DEMUX, MSGL_V, ", -%clang %s", - *stream_type, lang->value); - if (title && title->value) - mp_msg(MSGT_DEMUX, MSGL_V, ", %s", title->value); - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); - } -} - -static demuxer_t *demux_open_lavf(demuxer_t *demuxer) -{ - struct MPOpts *opts = demuxer->opts; - struct lavfdopts *lavfdopts = &opts->lavfdopts; - AVFormatContext *avfc; - AVDictionaryEntry *t = NULL; - lavf_priv_t *priv = demuxer->priv; - int i; - char mp_filename[256] = "mp:"; - - stream_seek(demuxer->stream, 0); - - avfc = avformat_alloc_context(); - - if (lavfdopts->cryptokey) - parse_cryptokey(avfc, lavfdopts->cryptokey); - if (matches_avinputformat_name(priv, "avi")) { - /* for avi libavformat returns the avi timestamps in .dts, - * some made-up stuff that's not really pts in .pts */ - priv->use_dts = true; - demuxer->timestamp_type = TIMESTAMP_TYPE_SORT; - } else { - if (opts->user_correct_pts != 0) - avfc->flags |= AVFMT_FLAG_GENPTS; - } - if (index_mode == 0) - avfc->flags |= AVFMT_FLAG_IGNIDX; - - if (lavfdopts->probesize) { - if (av_opt_set_int(avfc, "probesize", lavfdopts->probesize, 0) < 0) - mp_msg(MSGT_HEADER, MSGL_ERR, - "demux_lavf, couldn't set option probesize to %u\n", - lavfdopts->probesize); - } - if (lavfdopts->analyzeduration) { - if (av_opt_set_int(avfc, "analyzeduration", - lavfdopts->analyzeduration * AV_TIME_BASE, 0) < 0) - mp_msg(MSGT_HEADER, MSGL_ERR, "demux_lavf, couldn't set option " - "analyzeduration to %u\n", lavfdopts->analyzeduration); - } - - if (lavfdopts->avopt) { - if (parse_avopts(avfc, lavfdopts->avopt) < 0) { - mp_msg(MSGT_HEADER, MSGL_ERR, - "Your options /%s/ look like gibberish to me pal\n", - lavfdopts->avopt); - return NULL; - } - } - - if (demuxer->stream->url) { - if (demuxer->stream->lavf_type && !strcmp(demuxer->stream->lavf_type, - "rtsp")) { - // Remove possible leading ffmpeg:// or lavf:// - char *name = strstr(demuxer->stream->url, "rtsp:"); - av_strlcpy(mp_filename, name, sizeof(mp_filename)); - } else - av_strlcat(mp_filename, demuxer->stream->url, sizeof(mp_filename)); - } else - av_strlcat(mp_filename, "foobar.dummy", sizeof(mp_filename)); - - if (!(priv->avif->flags & AVFMT_NOFILE)) { - priv->pb = avio_alloc_context(priv->buffer, BIO_BUFFER_SIZE, 0, - demuxer, mp_read, NULL, mp_seek); - priv->pb->read_seek = mp_read_seek; - priv->pb->seekable = demuxer->stream->end_pos - && (demuxer->stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK - ? AVIO_SEEKABLE_NORMAL : 0; - avfc->pb = priv->pb; - } - - if (avformat_open_input(&avfc, mp_filename, priv->avif, NULL) < 0) { - mp_msg(MSGT_HEADER, MSGL_ERR, - "LAVF_header: avformat_open_input() failed\n"); - return NULL; - } - - priv->avfc = avfc; - - if (avformat_find_stream_info(avfc, NULL) < 0) { - mp_msg(MSGT_HEADER, MSGL_ERR, - "LAVF_header: av_find_stream_info() failed\n"); - return NULL; - } - - /* Add metadata. */ - while ((t = av_dict_get(avfc->metadata, "", t, - AV_DICT_IGNORE_SUFFIX))) - demux_info_add(demuxer, t->key, t->value); - - for (i = 0; i < avfc->nb_chapters; i++) { - AVChapter *c = avfc->chapters[i]; - uint64_t start = av_rescale_q(c->start, c->time_base, - (AVRational){1, 1000000000}); - uint64_t end = av_rescale_q(c->end, c->time_base, - (AVRational){1, 1000000000}); - t = av_dict_get(c->metadata, "title", NULL, 0); - demuxer_add_chapter(demuxer, t ? bstr0(t->value) : bstr0(NULL), - start, end); - } - - for (i = 0; i < avfc->nb_streams; i++) - handle_stream(demuxer, avfc, i); - priv->nb_streams_last = avfc->nb_streams; - - if (avfc->nb_programs) { - int p; - for (p = 0; p < avfc->nb_programs; p++) { - AVProgram *program = avfc->programs[p]; - t = av_dict_get(program->metadata, "title", NULL, 0); - mp_msg(MSGT_HEADER, MSGL_INFO, "LAVF: Program %d %s\n", - program->id, t ? t->value : ""); - mp_msg(MSGT_IDENTIFY, MSGL_V, "PROGRAM_ID=%d\n", program->id); - } - } - - mp_msg(MSGT_HEADER, MSGL_V, "LAVF: %d audio and %d video streams found\n", - priv->audio_streams, priv->video_streams); - mp_msg(MSGT_HEADER, MSGL_V, "LAVF: build %d\n", LIBAVFORMAT_BUILD); - demuxer->audio->id = -2; // wait for higher-level code to select track - if (!priv->video_streams) { - if (!priv->audio_streams) { - mp_msg(MSGT_HEADER, MSGL_ERR, - "LAVF: no audio or video headers found - broken file?\n"); - return NULL; - } - demuxer->video->id = -2; // audio-only - } - - // disabled because unreliable per-stream bitrate values returned - // by libavformat trigger this heuristic incorrectly and break things -#if 0 - /* libavformat sets bitrate for mpeg based on pts at start and end - * of file, which fails for files with pts resets. So calculate our - * own bitrate estimate. */ - if (priv->avif->flags & AVFMT_TS_DISCONT) { - for (int i = 0; i < avfc->nb_streams; i++) - priv->bitrate += avfc->streams[i]->codec->bit_rate; - /* pts-based is more accurate if there are no resets; try to make - * a somewhat reasonable guess */ - if (!avfc->duration || avfc->duration == AV_NOPTS_VALUE - || priv->bitrate && (avfc->bit_rate < priv->bitrate / 2 - || avfc->bit_rate > priv->bitrate * 2)) - priv->seek_by_bytes = true; - if (!priv->bitrate) - priv->bitrate = 1440000; - } -#endif - demuxer->accurate_seek = !priv->seek_by_bytes; - - return demuxer; -} - -static void check_internet_radio_hack(struct demuxer *demuxer) -{ - struct lavf_priv *priv = demuxer->priv; - struct AVFormatContext *avfc = priv->avfc; - - if (!matches_avinputformat_name(priv, "ogg")) - return; - if (priv->nb_streams_last == avfc->nb_streams) - return; - if (avfc->nb_streams - priv->nb_streams_last == 1 - && priv->video_streams == 0 && priv->sub_streams == 0 - && demuxer->a_streams[priv->audio_streams - 1]->format == 0x566f // vorbis - && (priv->audio_streams == 2 || priv->internet_radio_hack) - && demuxer->a_streams[0]->format == 0x566f) { - // extradata match could be checked but would require parsing - // headers, as the comment section will vary - if (!priv->internet_radio_hack) { - mp_msg(MSGT_DEMUX, MSGL_V, - "[lavf] enabling internet ogg radio hack\n"); - } - priv->internet_radio_hack = true; - // use new per-track metadata as global metadata - AVDictionaryEntry *t = NULL; - AVStream *stream = avfc->streams[avfc->nb_streams - 1]; - while ((t = av_dict_get(stream->metadata, "", t, - AV_DICT_IGNORE_SUFFIX))) - demux_info_add(demuxer, t->key, t->value); - } else { - if (priv->internet_radio_hack) - mp_tmsg(MSGT_DEMUX, MSGL_WARN, "[lavf] Internet radio ogg hack " - "was enabled, but stream characteristics changed.\n" - "This may or may not work.\n"); - priv->internet_radio_hack = false; - } -} - -static int destroy_avpacket(void *pkt) -{ - av_free_packet(pkt); - return 0; -} - -static int demux_lavf_fill_buffer(demuxer_t *demux, demux_stream_t *dsds) -{ - lavf_priv_t *priv = demux->priv; - demux_packet_t *dp; - demux_stream_t *ds; - int id; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_lavf_fill_buffer()\n"); - - demux->filepos = stream_tell(demux->stream); - - AVPacket *pkt = talloc(NULL, AVPacket); - if (av_read_frame(priv->avfc, pkt) < 0) { - talloc_free(pkt); - return 0; - } - talloc_set_destructor(pkt, destroy_avpacket); - - // handle any new streams that might have been added - for (id = priv->nb_streams_last; id < priv->avfc->nb_streams; id++) - handle_stream(demux, priv->avfc, id); - check_internet_radio_hack(demux); - - priv->nb_streams_last = priv->avfc->nb_streams; - - id = pkt->stream_index; - - assert(id >= 0 && id < MAX_S_STREAMS); - if (demux->s_streams[id] && demux->sub->id == -1 && - demux->s_streams[id]->gsh->demuxer_id == priv->autoselect_sub) - { - priv->autoselect_sub = -1; - demux->sub->id = id; - } - - if (id == demux->audio->id || priv->internet_radio_hack) { - // audio - ds = demux->audio; - if (!ds->sh) { - ds->sh = demux->a_streams[id]; - mp_msg(MSGT_DEMUX, MSGL_V, "Auto-selected LAVF audio ID = %d\n", - ds->id); - } - } else if (id == demux->video->id) { - // video - ds = demux->video; - if (!ds->sh) { - ds->sh = demux->v_streams[id]; - mp_msg(MSGT_DEMUX, MSGL_V, "Auto-selected LAVF video ID = %d\n", - ds->id); - } - } else if (id == demux->sub->id) { - // subtitle - ds = demux->sub; - } else { - talloc_free(pkt); - return 1; - } - - // If the packet has pointers to temporary fields that could be - // overwritten/freed by next av_read_frame(), copy them to persistent - // allocations so we can safely queue the packet for any length of time. - if (av_dup_packet(pkt) < 0) - abort(); - dp = new_demux_packet_fromdata(pkt->data, pkt->size); - dp->avpacket = pkt; - - int64_t ts = priv->use_dts ? pkt->dts : pkt->pts; - if (ts != AV_NOPTS_VALUE) { - dp->pts = ts * av_q2d(priv->avfc->streams[id]->time_base); - priv->last_pts = dp->pts * AV_TIME_BASE; - // always set duration for subtitles, even if AV_PKT_FLAG_KEY isn't set, - // otherwise they will stay on screen to long if e.g. ASS is demuxed - // from mkv - if ((ds == demux->sub || (pkt->flags & AV_PKT_FLAG_KEY)) && - pkt->convergence_duration > 0) - dp->duration = pkt->convergence_duration * - av_q2d(priv->avfc->streams[id]->time_base); - } - dp->pos = demux->filepos; - dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY; - // append packet to DS stream: - ds_add_packet(ds, dp); - return 1; -} - -static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, - float audio_delay, int flags) -{ - lavf_priv_t *priv = demuxer->priv; - int avsflags = 0; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_seek_lavf(%p, %f, %f, %d)\n", - demuxer, rel_seek_secs, audio_delay, flags); - - if (priv->seek_by_bytes) { - int64_t pos = demuxer->filepos; - rel_seek_secs *= priv->bitrate / 8; - pos += rel_seek_secs; - av_seek_frame(priv->avfc, -1, pos, AVSEEK_FLAG_BYTE); - return; - } - - if (flags & SEEK_ABSOLUTE) - priv->last_pts = 0; - else if (rel_seek_secs < 0) - avsflags = AVSEEK_FLAG_BACKWARD; - if (flags & SEEK_FORWARD) - avsflags = 0; - else if (flags & SEEK_BACKWARD) - avsflags = AVSEEK_FLAG_BACKWARD; - if (flags & SEEK_FACTOR) { - if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE) - return; - priv->last_pts += rel_seek_secs * priv->avfc->duration; - } else - priv->last_pts += rel_seek_secs * AV_TIME_BASE; - if (av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags) < 0) { - avsflags ^= AVSEEK_FLAG_BACKWARD; - av_seek_frame(priv->avfc, -1, priv->last_pts, avsflags); - } -} - -static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) -{ - lavf_priv_t *priv = demuxer->priv; - - switch (cmd) { - case DEMUXER_CTRL_CORRECT_PTS: - return DEMUXER_CTRL_OK; - case DEMUXER_CTRL_GET_TIME_LENGTH: - if (priv->seek_by_bytes) { - /* Our bitrate estimate may be better than would be used in - * otherwise similar fallback code at higher level */ - if (demuxer->movi_end <= 0) - return DEMUXER_CTRL_DONTKNOW; - *(double *)arg = (demuxer->movi_end - demuxer->movi_start) * 8 / - priv->bitrate; - return DEMUXER_CTRL_GUESS; - } - if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE) - return DEMUXER_CTRL_DONTKNOW; - - *((double *)arg) = (double)priv->avfc->duration / AV_TIME_BASE; - return DEMUXER_CTRL_OK; - - case DEMUXER_CTRL_GET_PERCENT_POS: - if (priv->seek_by_bytes) - return DEMUXER_CTRL_DONTKNOW; // let it use the fallback code - if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE) - return DEMUXER_CTRL_DONTKNOW; - - *((int *)arg) = (int)((priv->last_pts - priv->avfc->start_time) * 100 / - priv->avfc->duration); - return DEMUXER_CTRL_OK; - case DEMUXER_CTRL_SWITCH_AUDIO: - case DEMUXER_CTRL_SWITCH_VIDEO: - { - int id = *((int *)arg); - int newid = -2; - int i, curridx = -1; - int nstreams, *pstreams; - demux_stream_t *ds; - |