1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * AVI muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2000 Fabrice Bellard 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include <math.h> 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "internal.h" 26cabdff1aSopenharmony_ci#include "avi.h" 27cabdff1aSopenharmony_ci#include "avio_internal.h" 28cabdff1aSopenharmony_ci#include "config_components.h" 29cabdff1aSopenharmony_ci#include "riff.h" 30cabdff1aSopenharmony_ci#include "mpegts.h" 31cabdff1aSopenharmony_ci#include "rawutils.h" 32cabdff1aSopenharmony_ci#include "libavformat/avlanguage.h" 33cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 34cabdff1aSopenharmony_ci#include "libavutil/avutil.h" 35cabdff1aSopenharmony_ci#include "libavutil/internal.h" 36cabdff1aSopenharmony_ci#include "libavutil/dict.h" 37cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 38cabdff1aSopenharmony_ci#include "libavutil/timestamp.h" 39cabdff1aSopenharmony_ci#include "libavutil/opt.h" 40cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 41cabdff1aSopenharmony_ci#include "libavcodec/raw.h" 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci/* 44cabdff1aSopenharmony_ci * TODO: 45cabdff1aSopenharmony_ci * - fill all fields if non streamed (nb_frames for example) 46cabdff1aSopenharmony_ci */ 47cabdff1aSopenharmony_ci 48cabdff1aSopenharmony_citypedef struct AVIIentry { 49cabdff1aSopenharmony_ci char tag[4]; 50cabdff1aSopenharmony_ci unsigned int flags; 51cabdff1aSopenharmony_ci unsigned int pos; 52cabdff1aSopenharmony_ci unsigned int len; 53cabdff1aSopenharmony_ci} AVIIentry; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci#define AVI_INDEX_CLUSTER_SIZE 16384 56cabdff1aSopenharmony_ci#define AVI_MASTER_INDEX_PREFIX_SIZE (8+2+1+1+4+8+4+4) 57cabdff1aSopenharmony_ci#define AVI_MASTER_INDEX_ENTRY_SIZE 16 /* bytes per entry */ 58cabdff1aSopenharmony_ci#define AVI_MASTER_INDEX_SIZE_DEFAULT 256 /* number of entries */ 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_citypedef struct AVIIndex { 61cabdff1aSopenharmony_ci int64_t indx_start; 62cabdff1aSopenharmony_ci int64_t audio_strm_offset; 63cabdff1aSopenharmony_ci int entry; 64cabdff1aSopenharmony_ci int ents_allocated; 65cabdff1aSopenharmony_ci int master_odml_riff_id_base; 66cabdff1aSopenharmony_ci AVIIentry** cluster; 67cabdff1aSopenharmony_ci} AVIIndex; 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_citypedef struct AVIContext { 70cabdff1aSopenharmony_ci const AVClass *class; 71cabdff1aSopenharmony_ci AVPacket *empty_packet; 72cabdff1aSopenharmony_ci int64_t riff_start, movi_list, odml_list; 73cabdff1aSopenharmony_ci int64_t frames_hdr_all; 74cabdff1aSopenharmony_ci int riff_id; 75cabdff1aSopenharmony_ci int reserve_index_space; 76cabdff1aSopenharmony_ci int master_index_max_size; 77cabdff1aSopenharmony_ci int write_channel_mask; 78cabdff1aSopenharmony_ci int flipped_raw_rgb; 79cabdff1aSopenharmony_ci} AVIContext; 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_citypedef struct AVIStream { 82cabdff1aSopenharmony_ci int64_t frames_hdr_strm; 83cabdff1aSopenharmony_ci int64_t audio_strm_length; 84cabdff1aSopenharmony_ci int packet_count; 85cabdff1aSopenharmony_ci int entry; 86cabdff1aSopenharmony_ci int max_size; 87cabdff1aSopenharmony_ci int sample_requested; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci int64_t last_dts; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci AVIIndex indexes; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci int64_t strh_flags_offset; 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci uint32_t palette[AVPALETTE_COUNT]; 96cabdff1aSopenharmony_ci uint32_t old_palette[AVPALETTE_COUNT]; 97cabdff1aSopenharmony_ci int64_t pal_offset; 98cabdff1aSopenharmony_ci} AVIStream; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_cistatic int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt); 101cabdff1aSopenharmony_ci 102cabdff1aSopenharmony_cistatic inline AVIIentry *avi_get_ientry(const AVIIndex *idx, int ent_id) 103cabdff1aSopenharmony_ci{ 104cabdff1aSopenharmony_ci int cl = ent_id / AVI_INDEX_CLUSTER_SIZE; 105cabdff1aSopenharmony_ci int id = ent_id % AVI_INDEX_CLUSTER_SIZE; 106cabdff1aSopenharmony_ci return &idx->cluster[cl][id]; 107cabdff1aSopenharmony_ci} 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_cistatic int avi_add_ientry(AVFormatContext *s, int stream_index, char *tag, 110cabdff1aSopenharmony_ci unsigned int flags, unsigned int size) 111cabdff1aSopenharmony_ci{ 112cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 113cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 114cabdff1aSopenharmony_ci AVIStream *avist = s->streams[stream_index]->priv_data; 115cabdff1aSopenharmony_ci AVIIndex *idx = &avist->indexes; 116cabdff1aSopenharmony_ci int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; 117cabdff1aSopenharmony_ci int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci if (idx->ents_allocated <= idx->entry) { 120cabdff1aSopenharmony_ci idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1); 121cabdff1aSopenharmony_ci if (!idx->cluster) { 122cabdff1aSopenharmony_ci idx->ents_allocated = 0; 123cabdff1aSopenharmony_ci idx->entry = 0; 124cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 125cabdff1aSopenharmony_ci } 126cabdff1aSopenharmony_ci idx->cluster[cl] = 127cabdff1aSopenharmony_ci av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry)); 128cabdff1aSopenharmony_ci if (!idx->cluster[cl]) 129cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 130cabdff1aSopenharmony_ci idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci if (tag) 134cabdff1aSopenharmony_ci memcpy(idx->cluster[cl][id].tag, tag, 4); 135cabdff1aSopenharmony_ci else 136cabdff1aSopenharmony_ci memset(idx->cluster[cl][id].tag, 0, 4); 137cabdff1aSopenharmony_ci idx->cluster[cl][id].flags = flags; 138cabdff1aSopenharmony_ci idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list; 139cabdff1aSopenharmony_ci idx->cluster[cl][id].len = size; 140cabdff1aSopenharmony_ci avist->max_size = FFMAX(avist->max_size, size); 141cabdff1aSopenharmony_ci idx->entry++; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci return 0; 144cabdff1aSopenharmony_ci} 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_cistatic av_cold int avi_init(struct AVFormatContext *s) 147cabdff1aSopenharmony_ci{ 148cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (avi->reserve_index_space > 0) { 151cabdff1aSopenharmony_ci avi->master_index_max_size = (avi->reserve_index_space - AVI_MASTER_INDEX_PREFIX_SIZE) / AVI_MASTER_INDEX_ENTRY_SIZE; 152cabdff1aSopenharmony_ci avi->master_index_max_size = FFMAX(avi->master_index_max_size, 16); 153cabdff1aSopenharmony_ci } else 154cabdff1aSopenharmony_ci avi->master_index_max_size = AVI_MASTER_INDEX_SIZE_DEFAULT; 155cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "reserve_index_space:%d master_index_max_size:%d\n", 156cabdff1aSopenharmony_ci avi->reserve_index_space, avi->master_index_max_size); 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci return 1; /* stream initialization continues in avi_write_header */ 159cabdff1aSopenharmony_ci} 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_cistatic int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb, 162cabdff1aSopenharmony_ci const char *riff_tag, const char *list_tag) 163cabdff1aSopenharmony_ci{ 164cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 165cabdff1aSopenharmony_ci int64_t loff; 166cabdff1aSopenharmony_ci int i; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci avi->riff_id++; 169cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 170cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 171cabdff1aSopenharmony_ci avist->indexes.audio_strm_offset = avist->audio_strm_length; 172cabdff1aSopenharmony_ci avist->indexes.entry = 0; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci avi->riff_start = ff_start_tag(pb, "RIFF"); 176cabdff1aSopenharmony_ci ffio_wfourcc(pb, riff_tag); 177cabdff1aSopenharmony_ci loff = ff_start_tag(pb, "LIST"); 178cabdff1aSopenharmony_ci ffio_wfourcc(pb, list_tag); 179cabdff1aSopenharmony_ci return loff; 180cabdff1aSopenharmony_ci} 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_cistatic char *avi_stream2fourcc(char *tag, int index, enum AVMediaType type) 183cabdff1aSopenharmony_ci{ 184cabdff1aSopenharmony_ci tag[0] = '0' + index / 10; 185cabdff1aSopenharmony_ci tag[1] = '0' + index % 10; 186cabdff1aSopenharmony_ci if (type == AVMEDIA_TYPE_VIDEO) { 187cabdff1aSopenharmony_ci tag[2] = 'd'; 188cabdff1aSopenharmony_ci tag[3] = 'c'; 189cabdff1aSopenharmony_ci } else if (type == AVMEDIA_TYPE_SUBTITLE) { 190cabdff1aSopenharmony_ci // note: this is not an official code 191cabdff1aSopenharmony_ci tag[2] = 's'; 192cabdff1aSopenharmony_ci tag[3] = 'b'; 193cabdff1aSopenharmony_ci } else { 194cabdff1aSopenharmony_ci tag[2] = 'w'; 195cabdff1aSopenharmony_ci tag[3] = 'b'; 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci tag[4] = '\0'; 198cabdff1aSopenharmony_ci return tag; 199cabdff1aSopenharmony_ci} 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_cistatic int avi_write_counters(AVFormatContext *s, int riff_id) 202cabdff1aSopenharmony_ci{ 203cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 204cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 205cabdff1aSopenharmony_ci int n, au_byterate, au_ssize, au_scale, nb_frames = 0; 206cabdff1aSopenharmony_ci int64_t file_size; 207cabdff1aSopenharmony_ci AVCodecParameters *par; 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci file_size = avio_tell(pb); 210cabdff1aSopenharmony_ci for (n = 0; n < s->nb_streams; n++) { 211cabdff1aSopenharmony_ci AVIStream *avist = s->streams[n]->priv_data; 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci av_assert0(avist->frames_hdr_strm); 214cabdff1aSopenharmony_ci par = s->streams[n]->codecpar; 215cabdff1aSopenharmony_ci avio_seek(pb, avist->frames_hdr_strm, SEEK_SET); 216cabdff1aSopenharmony_ci ff_parse_specific_params(s->streams[n], &au_byterate, &au_ssize, &au_scale); 217cabdff1aSopenharmony_ci if (au_ssize == 0) 218cabdff1aSopenharmony_ci avio_wl32(pb, avist->packet_count); 219cabdff1aSopenharmony_ci else 220cabdff1aSopenharmony_ci avio_wl32(pb, avist->audio_strm_length / au_ssize); 221cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO) 222cabdff1aSopenharmony_ci nb_frames = FFMAX(nb_frames, avist->packet_count); 223cabdff1aSopenharmony_ci } 224cabdff1aSopenharmony_ci if (riff_id == 1) { 225cabdff1aSopenharmony_ci av_assert0(avi->frames_hdr_all); 226cabdff1aSopenharmony_ci avio_seek(pb, avi->frames_hdr_all, SEEK_SET); 227cabdff1aSopenharmony_ci avio_wl32(pb, nb_frames); 228cabdff1aSopenharmony_ci } 229cabdff1aSopenharmony_ci avio_seek(pb, file_size, SEEK_SET); 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci return 0; 232cabdff1aSopenharmony_ci} 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_cistatic void write_odml_master(AVFormatContext *s, int stream_index) 235cabdff1aSopenharmony_ci{ 236cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 237cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 238cabdff1aSopenharmony_ci AVStream *st = s->streams[stream_index]; 239cabdff1aSopenharmony_ci AVCodecParameters *par = st->codecpar; 240cabdff1aSopenharmony_ci AVIStream *avist = st->priv_data; 241cabdff1aSopenharmony_ci unsigned char tag[5]; 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci /* Starting to lay out AVI OpenDML master index. 244cabdff1aSopenharmony_ci * We want to make it JUNK entry for now, since we'd 245cabdff1aSopenharmony_ci * like to get away without making AVI an OpenDML one 246cabdff1aSopenharmony_ci * for compatibility reasons. */ 247cabdff1aSopenharmony_ci avist->indexes.indx_start = ff_start_tag(pb, "JUNK"); 248cabdff1aSopenharmony_ci avio_wl16(pb, 4); /* wLongsPerEntry */ 249cabdff1aSopenharmony_ci avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ 250cabdff1aSopenharmony_ci avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ 251cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */ 252cabdff1aSopenharmony_ci ffio_wfourcc(pb, avi_stream2fourcc(tag, stream_index, par->codec_type)); 253cabdff1aSopenharmony_ci /* dwChunkId */ 254cabdff1aSopenharmony_ci ffio_fill(pb, 0, 3 * 4 /* dwReserved[3] */ 255cabdff1aSopenharmony_ci + 16LL * avi->master_index_max_size); 256cabdff1aSopenharmony_ci ff_end_tag(pb, avist->indexes.indx_start); 257cabdff1aSopenharmony_ci} 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_cistatic int avi_write_header(AVFormatContext *s) 260cabdff1aSopenharmony_ci{ 261cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 262cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 263cabdff1aSopenharmony_ci int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; 264cabdff1aSopenharmony_ci int64_t max_stream_duration = 0; 265cabdff1aSopenharmony_ci AVCodecParameters *video_par; 266cabdff1aSopenharmony_ci AVStream *video_st = NULL; 267cabdff1aSopenharmony_ci int64_t list1, list2, strh, strf; 268cabdff1aSopenharmony_ci AVDictionaryEntry *t = NULL; 269cabdff1aSopenharmony_ci int padding; 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_ci if (s->nb_streams > AVI_MAX_STREAM_COUNT) { 272cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "AVI does not support " 273cabdff1aSopenharmony_ci ">"AV_STRINGIFY(AVI_MAX_STREAM_COUNT)" streams\n"); 274cabdff1aSopenharmony_ci return AVERROR(EINVAL); 275cabdff1aSopenharmony_ci } 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci avi->empty_packet = ffformatcontext(s)->pkt; 278cabdff1aSopenharmony_ci 279cabdff1aSopenharmony_ci for (n = 0; n < s->nb_streams; n++) { 280cabdff1aSopenharmony_ci s->streams[n]->priv_data = av_mallocz(sizeof(AVIStream)); 281cabdff1aSopenharmony_ci if (!s->streams[n]->priv_data) 282cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 283cabdff1aSopenharmony_ci } 284cabdff1aSopenharmony_ci 285cabdff1aSopenharmony_ci /* header list */ 286cabdff1aSopenharmony_ci avi->riff_id = 0; 287cabdff1aSopenharmony_ci list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl"); 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci /* avi header */ 290cabdff1aSopenharmony_ci ffio_wfourcc(pb, "avih"); 291cabdff1aSopenharmony_ci avio_wl32(pb, 14 * 4); 292cabdff1aSopenharmony_ci bitrate = 0; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci video_par = NULL; 295cabdff1aSopenharmony_ci for (n = 0; n < s->nb_streams; n++) { 296cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[n]->codecpar; 297cabdff1aSopenharmony_ci AVStream *st = s->streams[n]; 298cabdff1aSopenharmony_ci bitrate = FFMIN(bitrate + par->bit_rate, INT32_MAX); 299cabdff1aSopenharmony_ci if (st->duration > 0) { 300cabdff1aSopenharmony_ci int64_t stream_duration = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); 301cabdff1aSopenharmony_ci max_stream_duration = FFMAX(stream_duration, max_stream_duration); 302cabdff1aSopenharmony_ci } 303cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO) { 304cabdff1aSopenharmony_ci video_par = par; 305cabdff1aSopenharmony_ci video_st = st; 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci } 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci /* guess master index size based on bitrate and duration */ 310cabdff1aSopenharmony_ci if (!avi->reserve_index_space) { 311cabdff1aSopenharmony_ci double duration_est, filesize_est; 312cabdff1aSopenharmony_ci if (s->duration > 0) 313cabdff1aSopenharmony_ci duration_est = (double)s->duration / AV_TIME_BASE; 314cabdff1aSopenharmony_ci else if (max_stream_duration > 0) 315cabdff1aSopenharmony_ci duration_est = (double)max_stream_duration / AV_TIME_BASE; 316cabdff1aSopenharmony_ci else 317cabdff1aSopenharmony_ci duration_est = 10 * 60 * 60; /* default to 10 hours */ 318cabdff1aSopenharmony_ci filesize_est = duration_est * (bitrate / 8) * 1.10; /* add 10% safety margin for muxer+bitrate */ 319cabdff1aSopenharmony_ci avi->master_index_max_size = FFMAX((int)ceil(filesize_est / AVI_MAX_RIFF_SIZE) + 1, 320cabdff1aSopenharmony_ci avi->master_index_max_size); 321cabdff1aSopenharmony_ci av_log(s, AV_LOG_DEBUG, "duration_est:%0.3f, filesize_est:%0.1fGiB, master_index_max_size:%d\n", 322cabdff1aSopenharmony_ci duration_est, filesize_est / (1024*1024*1024), avi->master_index_max_size); 323cabdff1aSopenharmony_ci } 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci nb_frames = 0; 326cabdff1aSopenharmony_ci 327cabdff1aSopenharmony_ci // TODO: should be avg_frame_rate 328cabdff1aSopenharmony_ci if (video_st) 329cabdff1aSopenharmony_ci avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_st->time_base.num / 330cabdff1aSopenharmony_ci video_st->time_base.den)); 331cabdff1aSopenharmony_ci else 332cabdff1aSopenharmony_ci avio_wl32(pb, 0); 333cabdff1aSopenharmony_ci avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */ 334cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* padding */ 335cabdff1aSopenharmony_ci if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) 336cabdff1aSopenharmony_ci avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ 337cabdff1aSopenharmony_ci else 338cabdff1aSopenharmony_ci avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ 339cabdff1aSopenharmony_ci avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */ 340cabdff1aSopenharmony_ci avio_wl32(pb, nb_frames); /* nb frames, filled later */ 341cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* initial frame */ 342cabdff1aSopenharmony_ci avio_wl32(pb, s->nb_streams); /* nb streams */ 343cabdff1aSopenharmony_ci avio_wl32(pb, 1024 * 1024); /* suggested buffer size */ 344cabdff1aSopenharmony_ci if (video_par) { 345cabdff1aSopenharmony_ci avio_wl32(pb, video_par->width); 346cabdff1aSopenharmony_ci avio_wl32(pb, video_par->height); 347cabdff1aSopenharmony_ci } else { 348cabdff1aSopenharmony_ci avio_wl32(pb, 0); 349cabdff1aSopenharmony_ci avio_wl32(pb, 0); 350cabdff1aSopenharmony_ci } 351cabdff1aSopenharmony_ci ffio_fill(pb, 0, 4 * 4); /* reserved */ 352cabdff1aSopenharmony_ci 353cabdff1aSopenharmony_ci /* stream list */ 354cabdff1aSopenharmony_ci for (i = 0; i < n; i++) { 355cabdff1aSopenharmony_ci AVStream *st = s->streams[i]; 356cabdff1aSopenharmony_ci AVCodecParameters *par = st->codecpar; 357cabdff1aSopenharmony_ci AVIStream *avist = st->priv_data; 358cabdff1aSopenharmony_ci list2 = ff_start_tag(pb, "LIST"); 359cabdff1aSopenharmony_ci ffio_wfourcc(pb, "strl"); 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci /* stream generic header */ 362cabdff1aSopenharmony_ci strh = ff_start_tag(pb, "strh"); 363cabdff1aSopenharmony_ci switch (par->codec_type) { 364cabdff1aSopenharmony_ci case AVMEDIA_TYPE_SUBTITLE: 365cabdff1aSopenharmony_ci // XSUB subtitles behave like video tracks, other subtitles 366cabdff1aSopenharmony_ci // are not (yet) supported. 367cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_XSUB) { 368cabdff1aSopenharmony_ci avpriv_report_missing_feature(s, "Subtitle streams other than DivX XSUB"); 369cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 372cabdff1aSopenharmony_ci ffio_wfourcc(pb, "vids"); 373cabdff1aSopenharmony_ci break; 374cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 375cabdff1aSopenharmony_ci ffio_wfourcc(pb, "auds"); 376cabdff1aSopenharmony_ci break; 377cabdff1aSopenharmony_ci// case AVMEDIA_TYPE_TEXT: 378cabdff1aSopenharmony_ci// ffio_wfourcc(pb, "txts"); 379cabdff1aSopenharmony_ci// break; 380cabdff1aSopenharmony_ci case AVMEDIA_TYPE_DATA: 381cabdff1aSopenharmony_ci ffio_wfourcc(pb, "dats"); 382cabdff1aSopenharmony_ci break; 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO || 385cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_XSUB) 386cabdff1aSopenharmony_ci avio_wl32(pb, par->codec_tag); 387cabdff1aSopenharmony_ci else 388cabdff1aSopenharmony_ci avio_wl32(pb, 1); 389cabdff1aSopenharmony_ci avist->strh_flags_offset = avio_tell(pb); 390cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* flags */ 391cabdff1aSopenharmony_ci avio_wl16(pb, 0); /* priority */ 392cabdff1aSopenharmony_ci avio_wl16(pb, 0); /* language */ 393cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* initial frame */ 394cabdff1aSopenharmony_ci 395cabdff1aSopenharmony_ci ff_parse_specific_params(st, &au_byterate, &au_ssize, &au_scale); 396cabdff1aSopenharmony_ci 397cabdff1aSopenharmony_ci if ( par->codec_type == AVMEDIA_TYPE_VIDEO 398cabdff1aSopenharmony_ci && par->codec_id != AV_CODEC_ID_XSUB 399cabdff1aSopenharmony_ci && au_byterate > 1000LL*au_scale) { 400cabdff1aSopenharmony_ci au_byterate = 600; 401cabdff1aSopenharmony_ci au_scale = 1; 402cabdff1aSopenharmony_ci } 403cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, au_scale, au_byterate); 404cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_XSUB) 405cabdff1aSopenharmony_ci au_scale = au_byterate = 0; 406cabdff1aSopenharmony_ci 407cabdff1aSopenharmony_ci avio_wl32(pb, au_scale); /* scale */ 408cabdff1aSopenharmony_ci avio_wl32(pb, au_byterate); /* rate */ 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* start */ 411cabdff1aSopenharmony_ci /* remember this offset to fill later */ 412cabdff1aSopenharmony_ci avist->frames_hdr_strm = avio_tell(pb); 413cabdff1aSopenharmony_ci if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) 414cabdff1aSopenharmony_ci /* FIXME: this may be broken, but who cares */ 415cabdff1aSopenharmony_ci avio_wl32(pb, AVI_MAX_RIFF_SIZE); 416cabdff1aSopenharmony_ci else 417cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* length, XXX: filled later */ 418cabdff1aSopenharmony_ci 419cabdff1aSopenharmony_ci /* suggested buffer size, is set to largest chunk size in avi_write_trailer */ 420cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO) 421cabdff1aSopenharmony_ci avio_wl32(pb, 1024 * 1024); 422cabdff1aSopenharmony_ci else if (par->codec_type == AVMEDIA_TYPE_AUDIO) 423cabdff1aSopenharmony_ci avio_wl32(pb, 12 * 1024); 424cabdff1aSopenharmony_ci else 425cabdff1aSopenharmony_ci avio_wl32(pb, 0); 426cabdff1aSopenharmony_ci avio_wl32(pb, -1); /* quality */ 427cabdff1aSopenharmony_ci avio_wl32(pb, au_ssize); /* sample size */ 428cabdff1aSopenharmony_ci avio_wl32(pb, 0); 429cabdff1aSopenharmony_ci if (par->width > 65535 || par->height > 65535) { 430cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "%dx%d dimensions are too big\n", par->width, par->height); 431cabdff1aSopenharmony_ci return AVERROR(EINVAL); 432cabdff1aSopenharmony_ci } 433cabdff1aSopenharmony_ci avio_wl16(pb, par->width); 434cabdff1aSopenharmony_ci avio_wl16(pb, par->height); 435cabdff1aSopenharmony_ci ff_end_tag(pb, strh); 436cabdff1aSopenharmony_ci 437cabdff1aSopenharmony_ci if (par->codec_type != AVMEDIA_TYPE_DATA) { 438cabdff1aSopenharmony_ci int ret, flags; 439cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt; 440cabdff1aSopenharmony_ci 441cabdff1aSopenharmony_ci strf = ff_start_tag(pb, "strf"); 442cabdff1aSopenharmony_ci switch (par->codec_type) { 443cabdff1aSopenharmony_ci case AVMEDIA_TYPE_SUBTITLE: 444cabdff1aSopenharmony_ci /* XSUB subtitles behave like video tracks, other subtitles 445cabdff1aSopenharmony_ci * are not (yet) supported. */ 446cabdff1aSopenharmony_ci if (par->codec_id != AV_CODEC_ID_XSUB) 447cabdff1aSopenharmony_ci break; 448cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 449cabdff1aSopenharmony_ci /* WMP expects RGB 5:5:5 rawvideo in avi to have bpp set to 16. */ 450cabdff1aSopenharmony_ci if ( !par->codec_tag 451cabdff1aSopenharmony_ci && par->codec_id == AV_CODEC_ID_RAWVIDEO 452cabdff1aSopenharmony_ci && par->format == AV_PIX_FMT_RGB555LE 453cabdff1aSopenharmony_ci && par->bits_per_coded_sample == 15) 454cabdff1aSopenharmony_ci par->bits_per_coded_sample = 16; 455cabdff1aSopenharmony_ci avist->pal_offset = avio_tell(pb) + 40; 456cabdff1aSopenharmony_ci ff_put_bmp_header(pb, par, 0, 0, avi->flipped_raw_rgb); 457cabdff1aSopenharmony_ci pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_AVI, 458cabdff1aSopenharmony_ci par->bits_per_coded_sample); 459cabdff1aSopenharmony_ci if ( !par->codec_tag 460cabdff1aSopenharmony_ci && par->codec_id == AV_CODEC_ID_RAWVIDEO 461cabdff1aSopenharmony_ci && par->format != pix_fmt 462cabdff1aSopenharmony_ci && par->format != AV_PIX_FMT_NONE) 463cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to avi, output file will be unreadable\n", 464cabdff1aSopenharmony_ci av_get_pix_fmt_name(par->format)); 465cabdff1aSopenharmony_ci 466cabdff1aSopenharmony_ci if (par->format == AV_PIX_FMT_PAL8) { 467cabdff1aSopenharmony_ci if (par->bits_per_coded_sample < 0 || par->bits_per_coded_sample > 8) { 468cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "PAL8 with %d bps is not allowed\n", par->bits_per_coded_sample); 469cabdff1aSopenharmony_ci return AVERROR(EINVAL); 470cabdff1aSopenharmony_ci } 471cabdff1aSopenharmony_ci } 472cabdff1aSopenharmony_ci 473cabdff1aSopenharmony_ci break; 474cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 475cabdff1aSopenharmony_ci flags = (avi->write_channel_mask == 0) ? FF_PUT_WAV_HEADER_SKIP_CHANNELMASK : 0; 476cabdff1aSopenharmony_ci if ((ret = ff_put_wav_header(s, pb, par, flags)) < 0) 477cabdff1aSopenharmony_ci return ret; 478cabdff1aSopenharmony_ci break; 479cabdff1aSopenharmony_ci default: 480cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 481cabdff1aSopenharmony_ci "Invalid or not supported codec type '%s' found in the input\n", 482cabdff1aSopenharmony_ci (char *)av_x_if_null(av_get_media_type_string(par->codec_type), "?")); 483cabdff1aSopenharmony_ci return AVERROR(EINVAL); 484cabdff1aSopenharmony_ci } 485cabdff1aSopenharmony_ci ff_end_tag(pb, strf); 486cabdff1aSopenharmony_ci if ((t = av_dict_get(st->metadata, "title", NULL, 0))) { 487cabdff1aSopenharmony_ci ff_riff_write_info_tag(s->pb, "strn", t->value); 488cabdff1aSopenharmony_ci t = NULL; 489cabdff1aSopenharmony_ci } 490cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_XSUB 491cabdff1aSopenharmony_ci && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { 492cabdff1aSopenharmony_ci const char* langstr = ff_convert_lang_to(t->value, AV_LANG_ISO639_1); 493cabdff1aSopenharmony_ci t = NULL; 494cabdff1aSopenharmony_ci if (langstr) { 495cabdff1aSopenharmony_ci char* str = av_asprintf("Subtitle - %s-xx;02", langstr); 496cabdff1aSopenharmony_ci if (!str) 497cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 498cabdff1aSopenharmony_ci ff_riff_write_info_tag(s->pb, "strn", str); 499cabdff1aSopenharmony_ci av_free(str); 500cabdff1aSopenharmony_ci } 501cabdff1aSopenharmony_ci } 502cabdff1aSopenharmony_ci } 503cabdff1aSopenharmony_ci 504cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 505cabdff1aSopenharmony_ci write_odml_master(s, i); 506cabdff1aSopenharmony_ci } 507cabdff1aSopenharmony_ci 508cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO && 509cabdff1aSopenharmony_ci st->sample_aspect_ratio.num > 0 && 510cabdff1aSopenharmony_ci st->sample_aspect_ratio.den > 0) { 511cabdff1aSopenharmony_ci int vprp = ff_start_tag(pb, "vprp"); 512cabdff1aSopenharmony_ci AVRational dar = av_mul_q(st->sample_aspect_ratio, 513cabdff1aSopenharmony_ci (AVRational) { par->width, 514cabdff1aSopenharmony_ci par->height }); 515cabdff1aSopenharmony_ci int num, den, fields, i; 516cabdff1aSopenharmony_ci av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); 517cabdff1aSopenharmony_ci if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_BB || 518cabdff1aSopenharmony_ci par->field_order == AV_FIELD_TB || par->field_order == AV_FIELD_BT) { 519cabdff1aSopenharmony_ci fields = 2; // interlaced 520cabdff1aSopenharmony_ci } else { 521cabdff1aSopenharmony_ci fields = 1; // progressive 522cabdff1aSopenharmony_ci } 523cabdff1aSopenharmony_ci 524cabdff1aSopenharmony_ci avio_wl32(pb, 0); // video format = unknown 525cabdff1aSopenharmony_ci avio_wl32(pb, 0); // video standard = unknown 526cabdff1aSopenharmony_ci // TODO: should be avg_frame_rate 527cabdff1aSopenharmony_ci avio_wl32(pb, (2LL*st->time_base.den + st->time_base.num - 1) / (2LL * st->time_base.num)); 528cabdff1aSopenharmony_ci avio_wl32(pb, par->width); 529cabdff1aSopenharmony_ci avio_wl32(pb, par->height); 530cabdff1aSopenharmony_ci avio_wl16(pb, den); 531cabdff1aSopenharmony_ci avio_wl16(pb, num); 532cabdff1aSopenharmony_ci avio_wl32(pb, par->width); 533cabdff1aSopenharmony_ci avio_wl32(pb, par->height); 534cabdff1aSopenharmony_ci avio_wl32(pb, fields); // fields per frame 535cabdff1aSopenharmony_ci 536cabdff1aSopenharmony_ci for (i = 0; i < fields; i++) { 537cabdff1aSopenharmony_ci int start_line; 538cabdff1aSopenharmony_ci // OpenDML v1.02 is not very specific on what value to use for 539cabdff1aSopenharmony_ci // start_line when frame data is not coming from a capturing device, 540cabdff1aSopenharmony_ci // so just use 0/1 depending on the field order for interlaced frames 541cabdff1aSopenharmony_ci if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_TB) { 542cabdff1aSopenharmony_ci start_line = (i == 0) ? 0 : 1; 543cabdff1aSopenharmony_ci } else if (par->field_order == AV_FIELD_BB || par->field_order == AV_FIELD_BT) { 544cabdff1aSopenharmony_ci start_line = (i == 0) ? 1 : 0; 545cabdff1aSopenharmony_ci } else { 546cabdff1aSopenharmony_ci start_line = 0; 547cabdff1aSopenharmony_ci } 548cabdff1aSopenharmony_ci 549cabdff1aSopenharmony_ci avio_wl32(pb, par->height / fields); // compressed bitmap height 550cabdff1aSopenharmony_ci avio_wl32(pb, par->width); // compressed bitmap width 551cabdff1aSopenharmony_ci avio_wl32(pb, par->height / fields); // valid bitmap height 552cabdff1aSopenharmony_ci avio_wl32(pb, par->width); // valid bitmap width 553cabdff1aSopenharmony_ci avio_wl32(pb, 0); // valid bitmap X offset 554cabdff1aSopenharmony_ci avio_wl32(pb, 0); // valid bitmap Y offset 555cabdff1aSopenharmony_ci avio_wl32(pb, 0); // valid X offset in T 556cabdff1aSopenharmony_ci avio_wl32(pb, start_line); // valid Y start line 557cabdff1aSopenharmony_ci } 558cabdff1aSopenharmony_ci ff_end_tag(pb, vprp); 559cabdff1aSopenharmony_ci } 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci ff_end_tag(pb, list2); 562cabdff1aSopenharmony_ci } 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 565cabdff1aSopenharmony_ci /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ 566cabdff1aSopenharmony_ci avi->odml_list = ff_start_tag(pb, "JUNK"); 567cabdff1aSopenharmony_ci ffio_wfourcc(pb, "odml"); 568cabdff1aSopenharmony_ci ffio_wfourcc(pb, "dmlh"); 569cabdff1aSopenharmony_ci avio_wl32(pb, 248); 570cabdff1aSopenharmony_ci ffio_fill(pb, 0, 248); 571cabdff1aSopenharmony_ci ff_end_tag(pb, avi->odml_list); 572cabdff1aSopenharmony_ci } 573cabdff1aSopenharmony_ci 574cabdff1aSopenharmony_ci ff_end_tag(pb, list1); 575cabdff1aSopenharmony_ci 576cabdff1aSopenharmony_ci ff_riff_write_info(s); 577cabdff1aSopenharmony_ci 578cabdff1aSopenharmony_ci 579cabdff1aSopenharmony_ci padding = s->metadata_header_padding; 580cabdff1aSopenharmony_ci if (padding < 0) 581cabdff1aSopenharmony_ci padding = 1016; 582cabdff1aSopenharmony_ci 583cabdff1aSopenharmony_ci /* some padding for easier tag editing */ 584cabdff1aSopenharmony_ci if (padding) { 585cabdff1aSopenharmony_ci list2 = ff_start_tag(pb, "JUNK"); 586cabdff1aSopenharmony_ci ffio_fill(pb, 0, FFALIGN((uint32_t)padding, 4)); 587cabdff1aSopenharmony_ci ff_end_tag(pb, list2); 588cabdff1aSopenharmony_ci } 589cabdff1aSopenharmony_ci 590cabdff1aSopenharmony_ci avi->movi_list = ff_start_tag(pb, "LIST"); 591cabdff1aSopenharmony_ci ffio_wfourcc(pb, "movi"); 592cabdff1aSopenharmony_ci 593cabdff1aSopenharmony_ci return 0; 594cabdff1aSopenharmony_ci} 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_cistatic void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size) 597cabdff1aSopenharmony_ci{ 598cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 599cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 600cabdff1aSopenharmony_ci AVIStream *avist = s->streams[stream_index]->priv_data; 601cabdff1aSopenharmony_ci int64_t pos; 602cabdff1aSopenharmony_ci int au_byterate, au_ssize, au_scale; 603cabdff1aSopenharmony_ci 604cabdff1aSopenharmony_ci pos = avio_tell(pb); 605cabdff1aSopenharmony_ci 606cabdff1aSopenharmony_ci /* Updating one entry in the AVI OpenDML master index */ 607cabdff1aSopenharmony_ci avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET); 608cabdff1aSopenharmony_ci ffio_wfourcc(pb, "indx"); /* enabling this entry */ 609cabdff1aSopenharmony_ci avio_skip(pb, 8); 610cabdff1aSopenharmony_ci avio_wl32(pb, avi->riff_id - avist->indexes.master_odml_riff_id_base); /* nEntriesInUse */ 611cabdff1aSopenharmony_ci avio_skip(pb, 16 * (avi->riff_id - avist->indexes.master_odml_riff_id_base)); 612cabdff1aSopenharmony_ci avio_wl64(pb, ix); /* qwOffset */ 613cabdff1aSopenharmony_ci avio_wl32(pb, size); /* dwSize */ 614cabdff1aSopenharmony_ci ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale); 615cabdff1aSopenharmony_ci if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) { 616cabdff1aSopenharmony_ci uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset); 617cabdff1aSopenharmony_ci if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) { 618cabdff1aSopenharmony_ci avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames"); 619cabdff1aSopenharmony_ci avist->sample_requested = 1; 620cabdff1aSopenharmony_ci } 621cabdff1aSopenharmony_ci avio_wl32(pb, audio_segm_size / au_ssize); /* dwDuration (sample count) */ 622cabdff1aSopenharmony_ci } else 623cabdff1aSopenharmony_ci avio_wl32(pb, avist->indexes.entry); /* dwDuration (packet count) */ 624cabdff1aSopenharmony_ci 625cabdff1aSopenharmony_ci avio_seek(pb, pos, SEEK_SET); 626cabdff1aSopenharmony_ci} 627cabdff1aSopenharmony_ci 628cabdff1aSopenharmony_cistatic int avi_write_ix(AVFormatContext *s) 629cabdff1aSopenharmony_ci{ 630cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 631cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 632cabdff1aSopenharmony_ci char tag[5]; 633cabdff1aSopenharmony_ci char ix_tag[] = "ix00"; 634cabdff1aSopenharmony_ci int i, j; 635cabdff1aSopenharmony_ci 636cabdff1aSopenharmony_ci av_assert0(pb->seekable & AVIO_SEEKABLE_NORMAL); 637cabdff1aSopenharmony_ci 638cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 639cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 640cabdff1aSopenharmony_ci if (avi->riff_id - avist->indexes.master_odml_riff_id_base == avi->master_index_max_size) { 641cabdff1aSopenharmony_ci int64_t pos; 642cabdff1aSopenharmony_ci int size = AVI_MASTER_INDEX_PREFIX_SIZE + AVI_MASTER_INDEX_ENTRY_SIZE * avi->master_index_max_size; 643cabdff1aSopenharmony_ci 644cabdff1aSopenharmony_ci pos = avio_tell(pb); 645cabdff1aSopenharmony_ci update_odml_entry(s, i, pos, size); 646cabdff1aSopenharmony_ci write_odml_master(s, i); 647cabdff1aSopenharmony_ci av_assert1(avio_tell(pb) - pos == size); 648cabdff1aSopenharmony_ci avist->indexes.master_odml_riff_id_base = avi->riff_id - 1; 649cabdff1aSopenharmony_ci } 650cabdff1aSopenharmony_ci av_assert0(avi->riff_id - avist->indexes.master_odml_riff_id_base < avi->master_index_max_size); 651cabdff1aSopenharmony_ci } 652cabdff1aSopenharmony_ci 653cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 654cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 655cabdff1aSopenharmony_ci int64_t ix; 656cabdff1aSopenharmony_ci 657cabdff1aSopenharmony_ci avi_stream2fourcc(tag, i, s->streams[i]->codecpar->codec_type); 658cabdff1aSopenharmony_ci ix_tag[3] = '0' + i; 659cabdff1aSopenharmony_ci 660cabdff1aSopenharmony_ci /* Writing AVI OpenDML leaf index chunk */ 661cabdff1aSopenharmony_ci ix = avio_tell(pb); 662cabdff1aSopenharmony_ci ffio_wfourcc(pb, ix_tag); /* ix?? */ 663cabdff1aSopenharmony_ci avio_wl32(pb, avist->indexes.entry * 8 + 24); 664cabdff1aSopenharmony_ci /* chunk size */ 665cabdff1aSopenharmony_ci avio_wl16(pb, 2); /* wLongsPerEntry */ 666cabdff1aSopenharmony_ci avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ 667cabdff1aSopenharmony_ci avio_w8(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */ 668cabdff1aSopenharmony_ci avio_wl32(pb, avist->indexes.entry); 669cabdff1aSopenharmony_ci /* nEntriesInUse */ 670cabdff1aSopenharmony_ci ffio_wfourcc(pb, tag); /* dwChunkId */ 671cabdff1aSopenharmony_ci avio_wl64(pb, avi->movi_list); /* qwBaseOffset */ 672cabdff1aSopenharmony_ci avio_wl32(pb, 0); /* dwReserved_3 (must be 0) */ 673cabdff1aSopenharmony_ci 674cabdff1aSopenharmony_ci for (j = 0; j < avist->indexes.entry; j++) { 675cabdff1aSopenharmony_ci AVIIentry *ie = avi_get_ientry(&avist->indexes, j); 676cabdff1aSopenharmony_ci avio_wl32(pb, ie->pos + 8); 677cabdff1aSopenharmony_ci avio_wl32(pb, ((uint32_t) ie->len & ~0x80000000) | 678cabdff1aSopenharmony_ci (ie->flags & 0x10 ? 0 : 0x80000000)); 679cabdff1aSopenharmony_ci } 680cabdff1aSopenharmony_ci 681cabdff1aSopenharmony_ci update_odml_entry(s, i, ix, avio_tell(pb) - ix); 682cabdff1aSopenharmony_ci } 683cabdff1aSopenharmony_ci return 0; 684cabdff1aSopenharmony_ci} 685cabdff1aSopenharmony_ci 686cabdff1aSopenharmony_cistatic int avi_write_idx1(AVFormatContext *s) 687cabdff1aSopenharmony_ci{ 688cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 689cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 690cabdff1aSopenharmony_ci int64_t idx_chunk; 691cabdff1aSopenharmony_ci int i; 692cabdff1aSopenharmony_ci char tag[5]; 693cabdff1aSopenharmony_ci 694cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 695cabdff1aSopenharmony_ci AVIStream *avist; 696cabdff1aSopenharmony_ci AVIIentry *ie = 0, *tie; 697cabdff1aSopenharmony_ci int empty, stream_id = -1; 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci idx_chunk = ff_start_tag(pb, "idx1"); 700cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 701cabdff1aSopenharmony_ci avist = s->streams[i]->priv_data; 702cabdff1aSopenharmony_ci avist->entry = 0; 703cabdff1aSopenharmony_ci } 704cabdff1aSopenharmony_ci 705cabdff1aSopenharmony_ci do { 706cabdff1aSopenharmony_ci empty = 1; 707cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 708cabdff1aSopenharmony_ci avist = s->streams[i]->priv_data; 709cabdff1aSopenharmony_ci if (avist->indexes.entry <= avist->entry) 710cabdff1aSopenharmony_ci continue; 711cabdff1aSopenharmony_ci 712cabdff1aSopenharmony_ci tie = avi_get_ientry(&avist->indexes, avist->entry); 713cabdff1aSopenharmony_ci if (empty || tie->pos < ie->pos) { 714cabdff1aSopenharmony_ci ie = tie; 715cabdff1aSopenharmony_ci stream_id = i; 716cabdff1aSopenharmony_ci } 717cabdff1aSopenharmony_ci empty = 0; 718cabdff1aSopenharmony_ci } 719cabdff1aSopenharmony_ci if (!empty) { 720cabdff1aSopenharmony_ci avist = s->streams[stream_id]->priv_data; 721cabdff1aSopenharmony_ci if (*ie->tag) 722cabdff1aSopenharmony_ci ffio_wfourcc(pb, ie->tag); 723cabdff1aSopenharmony_ci else { 724cabdff1aSopenharmony_ci avi_stream2fourcc(tag, stream_id, 725cabdff1aSopenharmony_ci s->streams[stream_id]->codecpar->codec_type); 726cabdff1aSopenharmony_ci ffio_wfourcc(pb, tag); 727cabdff1aSopenharmony_ci } 728cabdff1aSopenharmony_ci avio_wl32(pb, ie->flags); 729cabdff1aSopenharmony_ci avio_wl32(pb, ie->pos); 730cabdff1aSopenharmony_ci avio_wl32(pb, ie->len); 731cabdff1aSopenharmony_ci avist->entry++; 732cabdff1aSopenharmony_ci } 733cabdff1aSopenharmony_ci } while (!empty); 734cabdff1aSopenharmony_ci ff_end_tag(pb, idx_chunk); 735cabdff1aSopenharmony_ci 736cabdff1aSopenharmony_ci avi_write_counters(s, avi->riff_id); 737cabdff1aSopenharmony_ci } 738cabdff1aSopenharmony_ci return 0; 739cabdff1aSopenharmony_ci} 740cabdff1aSopenharmony_ci 741cabdff1aSopenharmony_cistatic int write_skip_frames(AVFormatContext *s, int stream_index, int64_t dts) 742cabdff1aSopenharmony_ci{ 743cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 744cabdff1aSopenharmony_ci AVIStream *avist = s->streams[stream_index]->priv_data; 745cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[stream_index]->codecpar; 746cabdff1aSopenharmony_ci 747cabdff1aSopenharmony_ci ff_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(dts), avist->packet_count, stream_index); 748cabdff1aSopenharmony_ci while (par->block_align == 0 && dts != AV_NOPTS_VALUE && 749cabdff1aSopenharmony_ci dts > avist->packet_count && par->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) { 750cabdff1aSopenharmony_ci 751cabdff1aSopenharmony_ci if (dts - avist->packet_count > 60000) { 752cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", dts - avist->packet_count); 753cabdff1aSopenharmony_ci return AVERROR(EINVAL); 754cabdff1aSopenharmony_ci } 755cabdff1aSopenharmony_ci 756cabdff1aSopenharmony_ci avi->empty_packet->stream_index = stream_index; 757cabdff1aSopenharmony_ci avi_write_packet_internal(s, avi->empty_packet); 758cabdff1aSopenharmony_ci ff_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count); 759cabdff1aSopenharmony_ci } 760cabdff1aSopenharmony_ci 761cabdff1aSopenharmony_ci return 0; 762cabdff1aSopenharmony_ci} 763cabdff1aSopenharmony_ci 764cabdff1aSopenharmony_cistatic int avi_write_packet(AVFormatContext *s, AVPacket *pkt) 765cabdff1aSopenharmony_ci{ 766cabdff1aSopenharmony_ci const int stream_index = pkt->stream_index; 767cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[stream_index]->codecpar; 768cabdff1aSopenharmony_ci int ret; 769cabdff1aSopenharmony_ci 770cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_H264 && par->codec_tag == MKTAG('H','2','6','4') && pkt->size) { 771cabdff1aSopenharmony_ci ret = ff_check_h264_startcode(s, s->streams[stream_index], pkt); 772cabdff1aSopenharmony_ci if (ret < 0) 773cabdff1aSopenharmony_ci return ret; 774cabdff1aSopenharmony_ci } 775cabdff1aSopenharmony_ci 776cabdff1aSopenharmony_ci if ((ret = write_skip_frames(s, stream_index, pkt->dts)) < 0) 777cabdff1aSopenharmony_ci return ret; 778cabdff1aSopenharmony_ci 779cabdff1aSopenharmony_ci if (!pkt->size) 780cabdff1aSopenharmony_ci return avi_write_packet_internal(s, pkt); /* Passthrough */ 781cabdff1aSopenharmony_ci 782cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO) { 783cabdff1aSopenharmony_ci AVIStream *avist = s->streams[stream_index]->priv_data; 784cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 785cabdff1aSopenharmony_ci AVPacket *opkt = pkt; 786cabdff1aSopenharmony_ci int reshuffle_ret; 787cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_RAWVIDEO && par->codec_tag == 0) { 788cabdff1aSopenharmony_ci int64_t bpc = par->bits_per_coded_sample != 15 ? par->bits_per_coded_sample : 16; 789cabdff1aSopenharmony_ci int expected_stride = ((par->width * bpc + 31) >> 5)*4; 790cabdff1aSopenharmony_ci reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, par, expected_stride); 791cabdff1aSopenharmony_ci if (reshuffle_ret < 0) 792cabdff1aSopenharmony_ci return reshuffle_ret; 793cabdff1aSopenharmony_ci } else 794cabdff1aSopenharmony_ci reshuffle_ret = 0; 795cabdff1aSopenharmony_ci if (par->format == AV_PIX_FMT_PAL8) { 796cabdff1aSopenharmony_ci ret = ff_get_packet_palette(s, opkt, reshuffle_ret, avist->palette); 797cabdff1aSopenharmony_ci if (ret < 0) 798cabdff1aSopenharmony_ci goto fail; 799cabdff1aSopenharmony_ci if (ret) { 800cabdff1aSopenharmony_ci int pal_size = 1 << par->bits_per_coded_sample; 801cabdff1aSopenharmony_ci int pc_tag, i; 802cabdff1aSopenharmony_ci 803cabdff1aSopenharmony_ci av_assert0(par->bits_per_coded_sample >= 0 && par->bits_per_coded_sample <= 8); 804cabdff1aSopenharmony_ci 805cabdff1aSopenharmony_ci if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && avist->pal_offset) { 806cabdff1aSopenharmony_ci int64_t cur_offset = avio_tell(pb); 807cabdff1aSopenharmony_ci avio_seek(pb, avist->pal_offset, SEEK_SET); 808cabdff1aSopenharmony_ci for (i = 0; i < pal_size; i++) { 809cabdff1aSopenharmony_ci uint32_t v = avist->palette[i]; 810cabdff1aSopenharmony_ci avio_wl32(pb, v & 0xffffff); 811cabdff1aSopenharmony_ci } 812cabdff1aSopenharmony_ci avio_seek(pb, cur_offset, SEEK_SET); 813cabdff1aSopenharmony_ci memcpy(avist->old_palette, avist->palette, pal_size * 4); 814cabdff1aSopenharmony_ci avist->pal_offset = 0; 815cabdff1aSopenharmony_ci } 816cabdff1aSopenharmony_ci if (memcmp(avist->palette, avist->old_palette, pal_size * 4)) { 817cabdff1aSopenharmony_ci unsigned char tag[5]; 818cabdff1aSopenharmony_ci avi_stream2fourcc(tag, stream_index, par->codec_type); 819cabdff1aSopenharmony_ci tag[2] = 'p'; tag[3] = 'c'; 820cabdff1aSopenharmony_ci if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { 821cabdff1aSopenharmony_ci if (avist->strh_flags_offset) { 822cabdff1aSopenharmony_ci int64_t cur_offset = avio_tell(pb); 823cabdff1aSopenharmony_ci avio_seek(pb, avist->strh_flags_offset, SEEK_SET); 824cabdff1aSopenharmony_ci avio_wl32(pb, AVISF_VIDEO_PALCHANGES); 825cabdff1aSopenharmony_ci avio_seek(pb, cur_offset, SEEK_SET); 826cabdff1aSopenharmony_ci avist->strh_flags_offset = 0; 827cabdff1aSopenharmony_ci } 828cabdff1aSopenharmony_ci ret = avi_add_ientry(s, stream_index, tag, AVIIF_NO_TIME, 829cabdff1aSopenharmony_ci pal_size * 4 + 4); 830cabdff1aSopenharmony_ci if (ret < 0) 831cabdff1aSopenharmony_ci goto fail; 832cabdff1aSopenharmony_ci } 833cabdff1aSopenharmony_ci pc_tag = ff_start_tag(pb, tag); 834cabdff1aSopenharmony_ci avio_w8(pb, 0); 835cabdff1aSopenharmony_ci avio_w8(pb, pal_size & 0xFF); 836cabdff1aSopenharmony_ci avio_wl16(pb, 0); // reserved 837cabdff1aSopenharmony_ci for (i = 0; i < pal_size; i++) { 838cabdff1aSopenharmony_ci uint32_t v = avist->palette[i]; 839cabdff1aSopenharmony_ci avio_wb32(pb, v<<8); 840cabdff1aSopenharmony_ci } 841cabdff1aSopenharmony_ci ff_end_tag(pb, pc_tag); 842cabdff1aSopenharmony_ci memcpy(avist->old_palette, avist->palette, pal_size * 4); 843cabdff1aSopenharmony_ci } 844cabdff1aSopenharmony_ci } 845cabdff1aSopenharmony_ci } 846cabdff1aSopenharmony_ci if (reshuffle_ret) { 847cabdff1aSopenharmony_ci ret = avi_write_packet_internal(s, pkt); 848cabdff1aSopenharmony_ci 849cabdff1aSopenharmony_cifail: 850cabdff1aSopenharmony_ci if (reshuffle_ret) 851cabdff1aSopenharmony_ci av_packet_free(&pkt); 852cabdff1aSopenharmony_ci return ret; 853cabdff1aSopenharmony_ci } 854cabdff1aSopenharmony_ci } 855cabdff1aSopenharmony_ci 856cabdff1aSopenharmony_ci return avi_write_packet_internal(s, pkt); 857cabdff1aSopenharmony_ci} 858cabdff1aSopenharmony_ci 859cabdff1aSopenharmony_cistatic int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt) 860cabdff1aSopenharmony_ci{ 861cabdff1aSopenharmony_ci unsigned char tag[5]; 862cabdff1aSopenharmony_ci unsigned int flags = 0; 863cabdff1aSopenharmony_ci const int stream_index = pkt->stream_index; 864cabdff1aSopenharmony_ci int size = pkt->size; 865cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 866cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 867cabdff1aSopenharmony_ci AVIStream *avist = s->streams[stream_index]->priv_data; 868cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[stream_index]->codecpar; 869cabdff1aSopenharmony_ci 870cabdff1aSopenharmony_ci if (pkt->dts != AV_NOPTS_VALUE) 871cabdff1aSopenharmony_ci avist->last_dts = pkt->dts + pkt->duration; 872cabdff1aSopenharmony_ci 873cabdff1aSopenharmony_ci avist->packet_count++; 874cabdff1aSopenharmony_ci 875cabdff1aSopenharmony_ci // Make sure to put an OpenDML chunk when the file size exceeds the limits 876cabdff1aSopenharmony_ci if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && 877cabdff1aSopenharmony_ci (avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) { 878cabdff1aSopenharmony_ci avi_write_ix(s); 879cabdff1aSopenharmony_ci ff_end_tag(pb, avi->movi_list); 880cabdff1aSopenharmony_ci 881cabdff1aSopenharmony_ci if (avi->riff_id == 1) 882cabdff1aSopenharmony_ci avi_write_idx1(s); 883cabdff1aSopenharmony_ci 884cabdff1aSopenharmony_ci ff_end_tag(pb, avi->riff_start); 885cabdff1aSopenharmony_ci avi->movi_list = avi_start_new_riff(s, pb, "AVIX", "movi"); 886cabdff1aSopenharmony_ci } 887cabdff1aSopenharmony_ci 888cabdff1aSopenharmony_ci avi_stream2fourcc(tag, stream_index, par->codec_type); 889cabdff1aSopenharmony_ci if (pkt->flags & AV_PKT_FLAG_KEY) 890cabdff1aSopenharmony_ci flags = 0x10; 891cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_AUDIO) 892cabdff1aSopenharmony_ci avist->audio_strm_length += size; 893cabdff1aSopenharmony_ci 894cabdff1aSopenharmony_ci if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { 895cabdff1aSopenharmony_ci int ret; 896cabdff1aSopenharmony_ci ret = avi_add_ientry(s, stream_index, NULL, flags, size); 897cabdff1aSopenharmony_ci if (ret < 0) 898cabdff1aSopenharmony_ci return ret; 899cabdff1aSopenharmony_ci } 900cabdff1aSopenharmony_ci 901cabdff1aSopenharmony_ci avio_write(pb, tag, 4); 902cabdff1aSopenharmony_ci avio_wl32(pb, size); 903cabdff1aSopenharmony_ci avio_write(pb, pkt->data, size); 904cabdff1aSopenharmony_ci if (size & 1) 905cabdff1aSopenharmony_ci avio_w8(pb, 0); 906cabdff1aSopenharmony_ci 907cabdff1aSopenharmony_ci return 0; 908cabdff1aSopenharmony_ci} 909cabdff1aSopenharmony_ci 910cabdff1aSopenharmony_cistatic int avi_write_trailer(AVFormatContext *s) 911cabdff1aSopenharmony_ci{ 912cabdff1aSopenharmony_ci AVIContext *avi = s->priv_data; 913cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 914cabdff1aSopenharmony_ci int res = 0; 915cabdff1aSopenharmony_ci int i, n, nb_frames; 916cabdff1aSopenharmony_ci int64_t file_size; 917cabdff1aSopenharmony_ci 918cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 919cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 920cabdff1aSopenharmony_ci write_skip_frames(s, i, avist->last_dts); 921cabdff1aSopenharmony_ci } 922cabdff1aSopenharmony_ci 923cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 924cabdff1aSopenharmony_ci if (avi->riff_id == 1) { 925cabdff1aSopenharmony_ci ff_end_tag(pb, avi->movi_list); 926cabdff1aSopenharmony_ci res = avi_write_idx1(s); 927cabdff1aSopenharmony_ci ff_end_tag(pb, avi->riff_start); 928cabdff1aSopenharmony_ci } else { 929cabdff1aSopenharmony_ci avi_write_ix(s); 930cabdff1aSopenharmony_ci ff_end_tag(pb, avi->movi_list); 931cabdff1aSopenharmony_ci ff_end_tag(pb, avi->riff_start); 932cabdff1aSopenharmony_ci 933cabdff1aSopenharmony_ci file_size = avio_tell(pb); 934cabdff1aSopenharmony_ci avio_seek(pb, avi->odml_list - 8, SEEK_SET); 935cabdff1aSopenharmony_ci ffio_wfourcc(pb, "LIST"); /* Making this AVI OpenDML one */ 936cabdff1aSopenharmony_ci avio_skip(pb, 16); 937cabdff1aSopenharmony_ci 938cabdff1aSopenharmony_ci for (n = nb_frames = 0; n < s->nb_streams; n++) { 939cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[n]->codecpar; 940cabdff1aSopenharmony_ci AVIStream *avist = s->streams[n]->priv_data; 941cabdff1aSopenharmony_ci 942cabdff1aSopenharmony_ci if (par->codec_type == AVMEDIA_TYPE_VIDEO) { 943cabdff1aSopenharmony_ci if (nb_frames < avist->packet_count) 944cabdff1aSopenharmony_ci nb_frames = avist->packet_count; 945cabdff1aSopenharmony_ci } else { 946cabdff1aSopenharmony_ci if (par->codec_id == AV_CODEC_ID_MP2 || 947cabdff1aSopenharmony_ci par->codec_id == AV_CODEC_ID_MP3) 948cabdff1aSopenharmony_ci nb_frames += avist->packet_count; 949cabdff1aSopenharmony_ci } 950cabdff1aSopenharmony_ci } 951cabdff1aSopenharmony_ci avio_wl32(pb, nb_frames); 952cabdff1aSopenharmony_ci avio_seek(pb, file_size, SEEK_SET); 953cabdff1aSopenharmony_ci 954cabdff1aSopenharmony_ci avi_write_counters(s, avi->riff_id); 955cabdff1aSopenharmony_ci } 956cabdff1aSopenharmony_ci } 957cabdff1aSopenharmony_ci 958cabdff1aSopenharmony_ci if (avi->riff_id >= avi->master_index_max_size) { 959cabdff1aSopenharmony_ci int index_space = AVI_MASTER_INDEX_PREFIX_SIZE + 960cabdff1aSopenharmony_ci AVI_MASTER_INDEX_ENTRY_SIZE * avi->riff_id; 961cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Output file not strictly OpenDML compliant, " 962cabdff1aSopenharmony_ci "consider re-muxing with 'reserve_index_space' option value >= %d\n", 963cabdff1aSopenharmony_ci index_space); 964cabdff1aSopenharmony_ci } 965cabdff1aSopenharmony_ci 966cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 967cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 968cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 969cabdff1aSopenharmony_ci avio_seek(pb, avist->frames_hdr_strm + 4, SEEK_SET); 970cabdff1aSopenharmony_ci avio_wl32(pb, avist->max_size); 971cabdff1aSopenharmony_ci } 972cabdff1aSopenharmony_ci } 973cabdff1aSopenharmony_ci 974cabdff1aSopenharmony_ci return res; 975cabdff1aSopenharmony_ci} 976cabdff1aSopenharmony_ci 977cabdff1aSopenharmony_cistatic void avi_deinit(AVFormatContext *s) 978cabdff1aSopenharmony_ci{ 979cabdff1aSopenharmony_ci for (int i = 0; i < s->nb_streams; i++) { 980cabdff1aSopenharmony_ci AVIStream *avist = s->streams[i]->priv_data; 981cabdff1aSopenharmony_ci if (!avist) 982cabdff1aSopenharmony_ci continue; 983cabdff1aSopenharmony_ci for (int j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++) 984cabdff1aSopenharmony_ci av_freep(&avist->indexes.cluster[j]); 985cabdff1aSopenharmony_ci av_freep(&avist->indexes.cluster); 986cabdff1aSopenharmony_ci avist->indexes.ents_allocated = avist->indexes.entry = 0; 987cabdff1aSopenharmony_ci } 988cabdff1aSopenharmony_ci} 989cabdff1aSopenharmony_ci 990cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(AVIContext, x) 991cabdff1aSopenharmony_ci#define ENC AV_OPT_FLAG_ENCODING_PARAM 992cabdff1aSopenharmony_cistatic const AVOption options[] = { 993cabdff1aSopenharmony_ci { "reserve_index_space", "reserve space (in bytes) at the beginning of the file for each stream index", OFFSET(reserve_index_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, ENC }, 994cabdff1aSopenharmony_ci { "write_channel_mask", "write channel mask into wave format header", OFFSET(write_channel_mask), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC }, 995cabdff1aSopenharmony_ci { "flipped_raw_rgb", "Raw RGB bitmaps are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, 996cabdff1aSopenharmony_ci { NULL }, 997cabdff1aSopenharmony_ci}; 998cabdff1aSopenharmony_ci 999cabdff1aSopenharmony_cistatic const AVClass avi_muxer_class = { 1000cabdff1aSopenharmony_ci .class_name = "AVI muxer", 1001cabdff1aSopenharmony_ci .item_name = av_default_item_name, 1002cabdff1aSopenharmony_ci .option = options, 1003cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 1004cabdff1aSopenharmony_ci}; 1005cabdff1aSopenharmony_ci 1006cabdff1aSopenharmony_ciconst AVOutputFormat ff_avi_muxer = { 1007cabdff1aSopenharmony_ci .name = "avi", 1008cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), 1009cabdff1aSopenharmony_ci .mime_type = "video/x-msvideo", 1010cabdff1aSopenharmony_ci .extensions = "avi", 1011cabdff1aSopenharmony_ci .priv_data_size = sizeof(AVIContext), 1012cabdff1aSopenharmony_ci .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3, 1013cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_MPEG4, 1014cabdff1aSopenharmony_ci .init = avi_init, 1015cabdff1aSopenharmony_ci .deinit = avi_deinit, 1016cabdff1aSopenharmony_ci .write_header = avi_write_header, 1017cabdff1aSopenharmony_ci .write_packet = avi_write_packet, 1018cabdff1aSopenharmony_ci .write_trailer = avi_write_trailer, 1019cabdff1aSopenharmony_ci .codec_tag = ff_riff_codec_tags_list, 1020cabdff1aSopenharmony_ci .priv_class = &avi_muxer_class, 1021cabdff1aSopenharmony_ci}; 1022