/* * FFM (ffserver live feed) demuxer * Copyright (c) 2001 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdint.h> #include "libavutil/imgutils.h"#include "libavutil/internal.h"#include "libavutil/intreadwrite.h"#include "libavutil/intfloat.h"#include "libavutil/opt.h"#include "libavutil/avassert.h"#include "libavutil/avstring.h"#include "libavutil/pixdesc.h"#include "libavcodec/internal.h"#include "avformat.h"#include "internal.h"#include "ffm.h"#include "avio_internal.h" static int ffm_is_avail_data(AVFormatContext *s, int size){ FFMContext *ffm = s->priv_data; int64_t pos, avail_size; ptrdiff_t len; len = ffm->packet_end - ffm->packet_ptr; if (size <= len) return 1; pos = avio_tell(s->pb); if (!ffm->write_index) { if (pos == ffm->file_size) return AVERROR_EOF; avail_size = ffm->file_size - pos; } else { if (pos == ffm->write_index) { /* exactly at the end of stream */ if (ffm->server_attached) return AVERROR(EAGAIN); else return AVERROR_INVALIDDATA; } else if (pos < ffm->write_index) { avail_size = ffm->write_index - pos; } else { avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE); } } avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len; if (size <= avail_size) return 1; else if (ffm->server_attached) return AVERROR(EAGAIN); else return AVERROR_INVALIDDATA;} static int ffm_resync(AVFormatContext *s, uint32_t state){ av_log(s, AV_LOG_ERROR, "resyncing\n"); while (state != PACKET_ID) { if (avio_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); return -1; } state = (state << 8) | avio_r8(s->pb); } return 0;} /* first is true if we read the frame header */static int ffm_read_data(AVFormatContext *s, uint8_t *buf, int size, int header){ FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int fill_size, size1, frame_offset; uint32_t id; ptrdiff_t len; int64_t last_pos = -1; size1 = size; while (size > 0) { redo: len = ffm->packet_end - ffm->packet_ptr; if (len < 0) return -1; if (len > size) len = size; if (len == 0) { if (avio_tell(pb) == ffm->file_size) { if (ffm->server_attached) { avio_seek(pb, ffm->packet_size, SEEK_SET); } else return AVERROR_EOF; } retry_read: if (pb->buffer_size != ffm->packet_size) { int64_t tell = avio_tell(pb); int ret = ffio_set_buf_size(pb, ffm->packet_size); if (ret < 0) return ret; avio_seek(pb, tell, SEEK_SET); } id = avio_rb16(pb); /* PACKET_ID */ if (id != PACKET_ID) { if (ffm_resync(s, id) < 0) return -1; last_pos = avio_tell(pb); } fill_size = avio_rb16(pb); ffm->dts = avio_rb64(pb); frame_offset = avio_rb16(pb); avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); if (ffm->packet_size < FFM_HEADER_SIZE + fill_size || frame_offset < 0) { return -1; } ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); /* if first packet or resynchronization packet, we must handle it specifically */ if (ffm->first_packet || (frame_offset & 0x8000)) { if (!frame_offset) { /* This packet has no frame headers in it */ if (avio_tell(pb) >= ffm->packet_size * 3LL) { int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos); seekback = FFMAX(seekback, 0); avio_seek(pb, -seekback, SEEK_CUR); goto retry_read; } /* This is bad, we cannot find a valid frame header */ return 0; } ffm->first_packet = 0; if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) { ffm->packet_end = ffm->packet_ptr; return -1; } ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; if (!header) break; } else { ffm->packet_ptr = ffm->packet; } goto redo; } memcpy(buf, ffm->packet_ptr, len); buf += len; ffm->packet_ptr += len; size -= len; header = 0; } return size1 - size;} /* ensure that actual seeking happens between FFM_PACKET_SIZE and file_size - FFM_PACKET_SIZE */static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1){ FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int64_t pos; pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); pos = FFMAX(pos, FFM_PACKET_SIZE); ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); return avio_seek(pb, pos, SEEK_SET);} static int64_t get_dts(AVFormatContext *s, int64_t pos){ AVIOContext *pb = s->pb; int64_t dts; ffm_seek1(s, pos); avio_skip(pb, 4); dts = avio_rb64(pb); ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0); return dts;} static void adjust_write_index(AVFormatContext *s){ FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int64_t pts; //int64_t orig_write_index = ffm->write_index; int64_t pos_min, pos_max; int64_t pts_start; int64_t ptr = avio_tell(pb); pos_min = 0; pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; pts_start = get_dts(s, pos_min); pts = get_dts(s, pos_max); if (pts - 100000 > pts_start) goto end; ffm->write_index = FFM_PACKET_SIZE; pts_start = get_dts(s, pos_min); pts = get_dts(s, pos_max); if (pts - 100000 <= pts_start) { while (1) { int64_t newpos; int64_t newpts; newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; if (newpos == pos_min) break; newpts = get_dts(s, newpos); if (newpts - 100000 <= pts) { pos_max = newpos; pts = newpts; } else { pos_min = newpos; } } ffm->write_index += pos_max; } end: avio_seek(pb, ptr, SEEK_SET);} static int ffm_append_recommended_configuration(AVStream *st, char **conf){ int ret; size_t newsize; av_assert0(conf && st); if (!*conf) return 0; if (!st->recommended_encoder_configuration) { st->recommended_encoder_configuration = *conf; *conf = 0; return 0; } newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2; if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0) return ret; av_strlcat(st->recommended_encoder_configuration, ",", newsize); av_strlcat(st->recommended_encoder_configuration, *conf, newsize); av_freep(conf); return 0;} #define VALIDATE_PARAMETER(parameter, name, check) { \ if (check) { \ av_log(s, AV_LOG_ERROR, "Invalid " name " %d\n", codecpar->parameter); \ ret = AVERROR_INVALIDDATA; \ goto fail; \ } \} static int ffm2_read_header(AVFormatContext *s){ FFMContext *ffm = s->priv_data; AVStream *st = NULL; AVIOContext *pb = s->pb; AVCodecContext *dummy_codec = NULL; AVCodecParameters *codecpar = NULL; const AVCodecDescriptor *codec_desc; int ret; int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1; AVCodec *enc; char *buffer; ffm->packet_size = avio_rb32(pb); if (ffm->packet_size != FFM_PACKET_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n", ffm->packet_size, FFM_PACKET_SIZE); ret = AVERROR_INVALIDDATA; goto fail; } ffm->write_index = avio_rb64(pb); /* get also filesize */ if (pb->seekable) { ffm->file_size = avio_size(pb); if (ffm->write_index && 0) adjust_write_index(s); } else { ffm->file_size = (UINT64_C(1) << 63) - 1; } dummy_codec = avcodec_alloc_context3(NULL); while(!avio_feof(pb)) { unsigned id = avio_rb32(pb); unsigned size = avio_rb32(pb); int64_t next = avio_tell(pb) + size; char rc_eq_buf[128]; int flags; if(!id) break; switch(id) { case MKBETAG('M', 'A', 'I', 'N'): if (f_main++) { ret = AVERROR(EINVAL); goto fail; } avio_rb32(pb); /* nb_streams */ avio_rb32(pb); /* total bitrate */ break; case MKBETAG('C', 'O', 'M', 'M'): f_cprv = f_stvi = f_stau = 0; st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avpriv_set_pts_info(st, 64, 1, 1000000); codecpar = st->codecpar; /* generic info */ codecpar->codec_id = avio_rb32(pb); codec_desc = avcodec_descriptor_get(codecpar->codec_id); if (!codec_desc) { av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); codecpar->codec_id = AV_CODEC_ID_NONE; ret = AVERROR_INVALIDDATA; goto fail; } codecpar->codec_type = avio_r8(pb); if (codecpar->codec_type != codec_desc->type) { av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", codec_desc->type, codecpar->codec_type); codecpar->codec_id = AV_CODEC_ID_NONE; codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; ret = AVERROR_INVALIDDATA; goto fail; } codecpar->bit_rate = avio_rb32(pb); if (codecpar->bit_rate < 0) { av_log(s, AV_LOG_ERROR, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); ret = AVERROR_INVALIDDATA; goto fail; } flags = avio_rb32(pb);#if FF_API_LAVF_AVCTXFF_DISABLE_DEPRECATION_WARNINGS st->codec->flags = flags;FF_ENABLE_DEPRECATION_WARNINGS#endif avio_rb32(pb); // flags2 avio_rb32(pb); // debug if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { int size = avio_rb32(pb); if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); ret = AVERROR_INVALIDDATA; goto fail; } codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); if (!codecpar->extradata) { ret = AVERROR(ENOMEM); goto fail; } codecpar->extradata_size = size; avio_read(pb, codecpar->extradata, size); } break; case MKBETAG('S', 'T', 'V', 'I'): if (f_stvi++ || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { ret = AVERROR(EINVAL); goto fail; } avio_rb32(pb); // time_base.num avio_rb32(pb); // time_base.den codecpar->width = avio_rb16(pb); codecpar->height = avio_rb16(pb); ret = av_image_check_size(codecpar->width, codecpar->height, 0, s); if (ret < 0) goto fail; avio_rb16(pb); // gop_size codecpar->format = avio_rb32(pb); if (!av_pix_fmt_desc_get(codecpar->format)) { av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); codecpar->format = AV_PIX_FMT_NONE; ret = AVERROR_INVALIDDATA; goto fail; } avio_r8(pb); // qmin avio_r8(pb); // qmax avio_r8(pb); // max_qdiff avio_rb16(pb); // qcompress / 10000.0 avio_rb16(pb); // qblur / 10000.0 avio_rb32(pb); // bit_rate_tolerance avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); avio_rb32(pb); // rc_max_rate avio_rb32(pb); // rc_min_rate avio_rb32(pb); // rc_buffer_size avio_rb64(pb); // i_quant_factor avio_rb64(pb); // b_quant_factor avio_rb64(pb); // i_quant_offset avio_rb64(pb); // b_quant_offset avio_rb32(pb); // dct_algo avio_rb32(pb); // strict_std_compliance avio_rb32(pb); // max_b_frames avio_rb32(pb); // mpeg_quant avio_rb32(pb); // intra_dc_precision avio_rb32(pb); // me_method avio_rb32(pb); // mb_decision avio_rb32(pb); // nsse_weight avio_rb32(pb); // frame_skip_cmp avio_rb64(pb); // rc_buffer_aggressivity codecpar->codec_tag = avio_rb32(pb); avio_r8(pb); // thread_count avio_rb32(pb); // coder_type avio_rb32(pb); // me_cmp avio_rb32(pb); // me_subpel_quality avio_rb32(pb); // me_range avio_rb32(pb); // keyint_min avio_rb32(pb); // scenechange_threshold avio_rb32(pb); // b_frame_strategy avio_rb64(pb); // qcompress avio_rb64(pb); // qblur avio_rb32(pb); // max_qdiff avio_rb32(pb); // refs break; case MKBETAG('S', 'T', 'A', 'U'): if (f_stau++ || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { ret = AVERROR(EINVAL); goto fail; } codecpar->sample_rate = avio_rb32(pb); VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) codecpar->channels = avio_rl16(pb); VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) codecpar->frame_size = avio_rl16(pb); VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) break; case MKBETAG('C', 'P', 'R', 'V'): if (f_cprv++) { ret = AVERROR(EINVAL); goto fail; } enc = avcodec_find_encoder(codecpar->codec_id); if (enc && enc->priv_data_size && enc->priv_class) { buffer = av_malloc(size + 1); if (!buffer) { ret = AVERROR(ENOMEM); goto fail; } avio_get_str(pb, size, buffer, size + 1); if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) goto fail; } break; case MKBETAG('S', '2', 'V', 'I'): if (f_stvi++ || !size || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { ret = AVERROR(EINVAL); goto fail; } buffer = av_malloc(size); if (!buffer) { ret = AVERROR(ENOMEM); goto fail; } avio_get_str(pb, INT_MAX, buffer, size); // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed avcodec_parameters_to_context(dummy_codec, codecpar); av_set_options_string(dummy_codec, buffer, "=", ","); avcodec_parameters_from_context(codecpar, dummy_codec); if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) goto fail; break; case MKBETAG('S', '2', 'A', 'U'): if (f_stau++ || !size || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { ret = AVERROR(EINVAL); goto fail; }Lines 1–500 of 878. Load more
/* * FFM (ffserver live feed) demuxer * Copyright (c) 2001 Fabrice Bellard * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdint.h> #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/pixdesc.h" #include "libavcodec/internal.h" #include "avformat.h" #include "internal.h" #include "ffm.h" #include "avio_internal.h" static int ffm_is_avail_data(AVFormatContext *s, int size) { FFMContext *ffm = s->priv_data; int64_t pos, avail_size; ptrdiff_t len; len = ffm->packet_end - ffm->packet_ptr; if (size <= len) return 1; pos = avio_tell(s->pb); if (!ffm->write_index) { if (pos == ffm->file_size) return AVERROR_EOF; avail_size = ffm->file_size - pos; } else { if (pos == ffm->write_index) { /* exactly at the end of stream */ if (ffm->server_attached) return AVERROR(EAGAIN); else return AVERROR_INVALIDDATA; } else if (pos < ffm->write_index) { avail_size = ffm->write_index - pos; } else { avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE); } } avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len; if (size <= avail_size) return 1; else if (ffm->server_attached) return AVERROR(EAGAIN); else return AVERROR_INVALIDDATA; } static int ffm_resync(AVFormatContext *s, uint32_t state) { av_log(s, AV_LOG_ERROR, "resyncing\n"); while (state != PACKET_ID) { if (avio_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); return -1; } state = (state << 8) | avio_r8(s->pb); } return 0; } /* first is true if we read the frame header */ static int ffm_read_data(AVFormatContext *s, uint8_t *buf, int size, int header) { FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int fill_size, size1, frame_offset; uint32_t id; ptrdiff_t len; int64_t last_pos = -1; size1 = size; while (size > 0) { redo: len = ffm->packet_end - ffm->packet_ptr; if (len < 0) return -1; if (len > size) len = size; if (len == 0) { if (avio_tell(pb) == ffm->file_size) { if (ffm->server_attached) { avio_seek(pb, ffm->packet_size, SEEK_SET); } else return AVERROR_EOF; } retry_read: if (pb->buffer_size != ffm->packet_size) { int64_t tell = avio_tell(pb); int ret = ffio_set_buf_size(pb, ffm->packet_size); if (ret < 0) return ret; avio_seek(pb, tell, SEEK_SET); } id = avio_rb16(pb); /* PACKET_ID */ if (id != PACKET_ID) { if (ffm_resync(s, id) < 0) return -1; last_pos = avio_tell(pb); } fill_size = avio_rb16(pb); ffm->dts = avio_rb64(pb); frame_offset = avio_rb16(pb); avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); if (ffm->packet_size < FFM_HEADER_SIZE + fill_size || frame_offset < 0) { return -1; } ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); /* if first packet or resynchronization packet, we must handle it specifically */ if (ffm->first_packet || (frame_offset & 0x8000)) { if (!frame_offset) { /* This packet has no frame headers in it */ if (avio_tell(pb) >= ffm->packet_size * 3LL) { int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos); seekback = FFMAX(seekback, 0); avio_seek(pb, -seekback, SEEK_CUR); goto retry_read; } /* This is bad, we cannot find a valid frame header */ return 0; } ffm->first_packet = 0; if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) { ffm->packet_end = ffm->packet_ptr; return -1; } ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; if (!header) break; } else { ffm->packet_ptr = ffm->packet; } goto redo; } memcpy(buf, ffm->packet_ptr, len); buf += len; ffm->packet_ptr += len; size -= len; header = 0; } return size1 - size; } /* ensure that actual seeking happens between FFM_PACKET_SIZE and file_size - FFM_PACKET_SIZE */ static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) { FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int64_t pos; pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); pos = FFMAX(pos, FFM_PACKET_SIZE); ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); return avio_seek(pb, pos, SEEK_SET); } static int64_t get_dts(AVFormatContext *s, int64_t pos) { AVIOContext *pb = s->pb; int64_t dts; ffm_seek1(s, pos); avio_skip(pb, 4); dts = avio_rb64(pb); ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0); return dts; } static void adjust_write_index(AVFormatContext *s) { FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; int64_t pts; //int64_t orig_write_index = ffm->write_index; int64_t pos_min, pos_max; int64_t pts_start; int64_t ptr = avio_tell(pb); pos_min = 0; pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; pts_start = get_dts(s, pos_min); pts = get_dts(s, pos_max); if (pts - 100000 > pts_start) goto end; ffm->write_index = FFM_PACKET_SIZE; pts_start = get_dts(s, pos_min); pts = get_dts(s, pos_max); if (pts - 100000 <= pts_start) { while (1) { int64_t newpos; int64_t newpts; newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; if (newpos == pos_min) break; newpts = get_dts(s, newpos); if (newpts - 100000 <= pts) { pos_max = newpos; pts = newpts; } else { pos_min = newpos; } } ffm->write_index += pos_max; } end: avio_seek(pb, ptr, SEEK_SET); } static int ffm_append_recommended_configuration(AVStream *st, char **conf) { int ret; size_t newsize; av_assert0(conf && st); if (!*conf) return 0; if (!st->recommended_encoder_configuration) { st->recommended_encoder_configuration = *conf; *conf = 0; return 0; } newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2; if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0) return ret; av_strlcat(st->recommended_encoder_configuration, ",", newsize); av_strlcat(st->recommended_encoder_configuration, *conf, newsize); av_freep(conf); return 0; } #define VALIDATE_PARAMETER(parameter, name, check) { \ if (check) { \ av_log(s, AV_LOG_ERROR, "Invalid " name " %d\n", codecpar->parameter); \ ret = AVERROR_INVALIDDATA; \ goto fail; \ } \ } static int ffm2_read_header(AVFormatContext *s) { FFMContext *ffm = s->priv_data; AVStream *st = NULL; AVIOContext *pb = s->pb; AVCodecContext *dummy_codec = NULL; AVCodecParameters *codecpar = NULL; const AVCodecDescriptor *codec_desc; int ret; int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1; AVCodec *enc; char *buffer; ffm->packet_size = avio_rb32(pb); if (ffm->packet_size != FFM_PACKET_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n", ffm->packet_size, FFM_PACKET_SIZE); ret = AVERROR_INVALIDDATA; goto fail; } ffm->write_index = avio_rb64(pb); /* get also filesize */ if (pb->seekable) { ffm->file_size = avio_size(pb); if (ffm->write_index && 0) adjust_write_index(s); } else { ffm->file_size = (UINT64_C(1) << 63) - 1; } dummy_codec = avcodec_alloc_context3(NULL); while(!avio_feof(pb)) { unsigned id = avio_rb32(pb); unsigned size = avio_rb32(pb); int64_t next = avio_tell(pb) + size; char rc_eq_buf[128]; int flags; if(!id) break; switch(id) { case MKBETAG('M', 'A', 'I', 'N'): if (f_main++) { ret = AVERROR(EINVAL); goto fail; } avio_rb32(pb); /* nb_streams */ avio_rb32(pb); /* total bitrate */ break; case MKBETAG('C', 'O', 'M', 'M'): f_cprv = f_stvi = f_stau = 0; st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avpriv_set_pts_info(st, 64, 1, 1000000); codecpar = st->codecpar; /* generic info */ codecpar->codec_id = avio_rb32(pb); codec_desc = avcodec_descriptor_get(codecpar->codec_id); if (!codec_desc) { av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); codecpar->codec_id = AV_CODEC_ID_NONE; ret = AVERROR_INVALIDDATA; goto fail; } codecpar->codec_type = avio_r8(pb); if (codecpar->codec_type != codec_desc->type) { av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", codec_desc->type, codecpar->codec_type); codecpar->codec_id = AV_CODEC_ID_NONE; codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; ret = AVERROR_INVALIDDATA; goto fail; } codecpar->bit_rate = avio_rb32(pb); if (codecpar->bit_rate < 0) { av_log(s, AV_LOG_ERROR, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); ret = AVERROR_INVALIDDATA; goto fail; } flags = avio_rb32(pb); #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS st->codec->flags = flags; FF_ENABLE_DEPRECATION_WARNINGS #endif avio_rb32(pb); // flags2 avio_rb32(pb); // debug if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { int size = avio_rb32(pb); if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); ret = AVERROR_INVALIDDATA; goto fail; } codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); if (!codecpar->extradata) { ret = AVERROR(ENOMEM); goto fail; } codecpar->extradata_size = size; avio_read(pb, codecpar->extradata, size); } break; case MKBETAG('S', 'T', 'V', 'I'): if (f_stvi++ || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { ret = AVERROR(EINVAL); goto fail; } avio_rb32(pb); // time_base.num avio_rb32(pb); // time_base.den codecpar->width = avio_rb16(pb); codecpar->height = avio_rb16(pb); ret = av_image_check_size(codecpar->width, codecpar->height, 0, s); if (ret < 0) goto fail; avio_rb16(pb); // gop_size codecpar->format = avio_rb32(pb); if (!av_pix_fmt_desc_get(codecpar->format)) { av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); codecpar->format = AV_PIX_FMT_NONE; ret = AVERROR_INVALIDDATA; goto fail; } avio_r8(pb); // qmin avio_r8(pb); // qmax avio_r8(pb); // max_qdiff avio_rb16(pb); // qcompress / 10000.0 avio_rb16(pb); // qblur / 10000.0 avio_rb32(pb); // bit_rate_tolerance avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); avio_rb32(pb); // rc_max_rate avio_rb32(pb); // rc_min_rate avio_rb32(pb); // rc_buffer_size avio_rb64(pb); // i_quant_factor avio_rb64(pb); // b_quant_factor avio_rb64(pb); // i_quant_offset avio_rb64(pb); // b_quant_offset avio_rb32(pb); // dct_algo avio_rb32(pb); // strict_std_compliance avio_rb32(pb); // max_b_frames avio_rb32(pb); // mpeg_quant avio_rb32(pb); // intra_dc_precision avio_rb32(pb); // me_method avio_rb32(pb); // mb_decision avio_rb32(pb); // nsse_weight avio_rb32(pb); // frame_skip_cmp avio_rb64(pb); // rc_buffer_aggressivity codecpar->codec_tag = avio_rb32(pb); avio_r8(pb); // thread_count avio_rb32(pb); // coder_type avio_rb32(pb); // me_cmp avio_rb32(pb); // me_subpel_quality avio_rb32(pb); // me_range avio_rb32(pb); // keyint_min avio_rb32(pb); // scenechange_threshold avio_rb32(pb); // b_frame_strategy avio_rb64(pb); // qcompress avio_rb64(pb); // qblur avio_rb32(pb); // max_qdiff avio_rb32(pb); // refs break; case MKBETAG('S', 'T', 'A', 'U'): if (f_stau++ || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { ret = AVERROR(EINVAL); goto fail; } codecpar->sample_rate = avio_rb32(pb); VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) codecpar->channels = avio_rl16(pb); VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) codecpar->frame_size = avio_rl16(pb); VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) break; case MKBETAG('C', 'P', 'R', 'V'): if (f_cprv++) { ret = AVERROR(EINVAL); goto fail; } enc = avcodec_find_encoder(codecpar->codec_id); if (enc && enc->priv_data_size && enc->priv_class) { buffer = av_malloc(size + 1); if (!buffer) { ret = AVERROR(ENOMEM); goto fail; } avio_get_str(pb, size, buffer, size + 1); if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) goto fail; } break; case MKBETAG('S', '2', 'V', 'I'): if (f_stvi++ || !size || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { ret = AVERROR(EINVAL); goto fail; } buffer = av_malloc(size); if (!buffer) { ret = AVERROR(ENOMEM); goto fail; } avio_get_str(pb, INT_MAX, buffer, size); // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed avcodec_parameters_to_context(dummy_codec, codecpar); av_set_options_string(dummy_codec, buffer, "=", ","); avcodec_parameters_from_context(codecpar, dummy_codec); if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) goto fail; break; case MKBETAG('S', '2', 'A', 'U'): if (f_stau++ || !size || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { ret = AVERROR(EINVAL); goto fail; }