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