ffmpeg / libavformat / asfenc.c @ b7f2fdde
History | View | Annotate | Download (30.4 KB)
1 |
/*
|
---|---|
2 |
* ASF muxer
|
3 |
* Copyright (c) 2000, 2001 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 |
#include "avformat.h" |
22 |
#include "metadata.h" |
23 |
#include "riff.h" |
24 |
#include "asf.h" |
25 |
#include "avio_internal.h" |
26 |
|
27 |
#undef NDEBUG
|
28 |
#include <assert.h> |
29 |
|
30 |
|
31 |
#define ASF_INDEXED_INTERVAL 10000000 |
32 |
#define ASF_INDEX_BLOCK 600 |
33 |
|
34 |
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 |
35 |
#define ASF_PACKET_ERROR_CORRECTION_FLAGS (\
|
36 |
ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT | \ |
37 |
ASF_PACKET_ERROR_CORRECTION_DATA_SIZE\ |
38 |
) |
39 |
|
40 |
#if (ASF_PACKET_ERROR_CORRECTION_FLAGS != 0) |
41 |
# define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 1 |
42 |
#else
|
43 |
# define ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE 0 |
44 |
#endif
|
45 |
|
46 |
#define ASF_PPI_PROPERTY_FLAGS (\
|
47 |
ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE | \ |
48 |
ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD | \ |
49 |
ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE | \ |
50 |
ASF_PL_FLAG_STREAM_NUMBER_LENGTH_FIELD_IS_BYTE \ |
51 |
) |
52 |
|
53 |
#define ASF_PPI_LENGTH_TYPE_FLAGS 0 |
54 |
|
55 |
#define ASF_PAYLOAD_FLAGS ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD
|
56 |
|
57 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
58 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 1 |
59 |
#endif
|
60 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
61 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 2 |
62 |
#endif
|
63 |
#if (ASF_PPI_FLAG_SEQUENCE_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_SEQUENCE_FIELD_SIZE))
|
64 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 4 |
65 |
#endif
|
66 |
#ifndef ASF_PPI_SEQUENCE_FIELD_SIZE
|
67 |
# define ASF_PPI_SEQUENCE_FIELD_SIZE 0 |
68 |
#endif
|
69 |
|
70 |
|
71 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
72 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 1 |
73 |
#endif
|
74 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
75 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 2 |
76 |
#endif
|
77 |
#if (ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE))
|
78 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 4 |
79 |
#endif
|
80 |
#ifndef ASF_PPI_PACKET_LENGTH_FIELD_SIZE
|
81 |
# define ASF_PPI_PACKET_LENGTH_FIELD_SIZE 0 |
82 |
#endif
|
83 |
|
84 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
85 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 1 |
86 |
#endif
|
87 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
88 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 2 |
89 |
#endif
|
90 |
#if (ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_DWORD == (ASF_PPI_LENGTH_TYPE_FLAGS & ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE))
|
91 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 4 |
92 |
#endif
|
93 |
#ifndef ASF_PPI_PADDING_LENGTH_FIELD_SIZE
|
94 |
# define ASF_PPI_PADDING_LENGTH_FIELD_SIZE 0 |
95 |
#endif
|
96 |
|
97 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
98 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 1 |
99 |
#endif
|
100 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
101 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 2 |
102 |
#endif
|
103 |
#if (ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE))
|
104 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 4 |
105 |
#endif
|
106 |
#ifndef ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE
|
107 |
# define ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE 0 |
108 |
#endif
|
109 |
|
110 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
111 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 1 |
112 |
#endif
|
113 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
114 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 2 |
115 |
#endif
|
116 |
#if (ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE))
|
117 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 4 |
118 |
#endif
|
119 |
#ifndef ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE
|
120 |
# define ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE 0 |
121 |
#endif
|
122 |
|
123 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
124 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 1 |
125 |
#endif
|
126 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_WORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
127 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 2 |
128 |
#endif
|
129 |
#if (ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_DWORD == (ASF_PPI_PROPERTY_FLAGS & ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE))
|
130 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 4 |
131 |
#endif
|
132 |
#ifndef ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE
|
133 |
# define ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE 0 |
134 |
#endif
|
135 |
|
136 |
#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_BYTE == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
|
137 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 1 |
138 |
#endif
|
139 |
#if (ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD == (ASF_PAYLOAD_FLAGS & ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE))
|
140 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 2 |
141 |
#endif
|
142 |
#ifndef ASF_PAYLOAD_LENGTH_FIELD_SIZE
|
143 |
# define ASF_PAYLOAD_LENGTH_FIELD_SIZE 0 |
144 |
#endif
|
145 |
|
146 |
#define PACKET_HEADER_MIN_SIZE (\
|
147 |
ASF_PACKET_ERROR_CORRECTION_FLAGS_FIELD_SIZE + \ |
148 |
ASF_PACKET_ERROR_CORRECTION_DATA_SIZE + \ |
149 |
1 + /*Length Type Flags*/ \ |
150 |
1 + /*Property Flags*/ \ |
151 |
ASF_PPI_PACKET_LENGTH_FIELD_SIZE + \ |
152 |
ASF_PPI_SEQUENCE_FIELD_SIZE + \ |
153 |
ASF_PPI_PADDING_LENGTH_FIELD_SIZE + \ |
154 |
4 + /*Send Time Field*/ \ |
155 |
2 /*Duration Field*/ \ |
156 |
) |
157 |
|
158 |
|
159 |
// Replicated Data shall be at least 8 bytes long.
|
160 |
#define ASF_PAYLOAD_REPLICATED_DATA_LENGTH 0x08 |
161 |
|
162 |
#define PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD (\
|
163 |
1 + /*Stream Number*/ \ |
164 |
ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE + \ |
165 |
ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE + \ |
166 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE + \ |
167 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH \ |
168 |
) |
169 |
|
170 |
#define PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS (\
|
171 |
1 + /*Stream Number*/ \ |
172 |
ASF_PAYLOAD_MEDIA_OBJECT_NUMBER_FIELD_SIZE + \ |
173 |
ASF_PAYLOAD_OFFSET_INTO_MEDIA_OBJECT_FIELD_SIZE + \ |
174 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH_FIELD_SIZE + \ |
175 |
ASF_PAYLOAD_REPLICATED_DATA_LENGTH + \ |
176 |
ASF_PAYLOAD_LENGTH_FIELD_SIZE \ |
177 |
) |
178 |
|
179 |
#define SINGLE_PAYLOAD_DATA_LENGTH (\
|
180 |
PACKET_SIZE - \ |
181 |
PACKET_HEADER_MIN_SIZE - \ |
182 |
PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD \ |
183 |
) |
184 |
|
185 |
#define MULTI_PAYLOAD_CONSTANT (\
|
186 |
PACKET_SIZE - \ |
187 |
PACKET_HEADER_MIN_SIZE - \ |
188 |
1 - /*Payload Flags*/ \ |
189 |
2*PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS \
|
190 |
) |
191 |
|
192 |
typedef struct { |
193 |
uint32_t seqno; |
194 |
int is_streamed;
|
195 |
ASFStream streams[128]; ///< it's max number and it's not that big |
196 |
/* non streamed additonnal info */
|
197 |
uint64_t nb_packets; ///< how many packets are there in the file, invalid if broadcasting
|
198 |
int64_t duration; ///< in 100ns units
|
199 |
/* packet filling */
|
200 |
unsigned char multi_payloads_present; |
201 |
int packet_size_left;
|
202 |
int packet_timestamp_start;
|
203 |
int packet_timestamp_end;
|
204 |
unsigned int packet_nb_payloads; |
205 |
uint8_t packet_buf[PACKET_SIZE]; |
206 |
AVIOContext pb; |
207 |
/* only for reading */
|
208 |
uint64_t data_offset; ///< beginning of the first data packet
|
209 |
|
210 |
int64_t last_indexed_pts; |
211 |
ASFIndex* index_ptr; |
212 |
uint32_t nb_index_count; |
213 |
uint32_t nb_index_memory_alloc; |
214 |
uint16_t maximum_packet; |
215 |
} ASFContext; |
216 |
|
217 |
static const AVCodecTag codec_asf_bmp_tags[] = { |
218 |
{ CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, |
219 |
{ CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, |
220 |
{ CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, |
221 |
{ CODEC_ID_NONE, 0 },
|
222 |
}; |
223 |
|
224 |
#define PREROLL_TIME 3100 |
225 |
|
226 |
static void put_guid(AVIOContext *s, const ff_asf_guid *g) |
227 |
{ |
228 |
assert(sizeof(*g) == 16); |
229 |
avio_write(s, *g, sizeof(*g));
|
230 |
} |
231 |
|
232 |
static void put_str16(AVIOContext *s, const char *tag) |
233 |
{ |
234 |
int len;
|
235 |
uint8_t *pb; |
236 |
AVIOContext *dyn_buf; |
237 |
if (url_open_dyn_buf(&dyn_buf) < 0) |
238 |
return;
|
239 |
|
240 |
avio_put_str16le(dyn_buf, tag); |
241 |
len = url_close_dyn_buf(dyn_buf, &pb); |
242 |
avio_wl16(s, len); |
243 |
avio_write(s, pb, len); |
244 |
av_freep(&pb); |
245 |
} |
246 |
|
247 |
static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g) |
248 |
{ |
249 |
int64_t pos; |
250 |
|
251 |
pos = avio_tell(pb); |
252 |
put_guid(pb, g); |
253 |
avio_wl64(pb, 24);
|
254 |
return pos;
|
255 |
} |
256 |
|
257 |
/* update header size */
|
258 |
static void end_header(AVIOContext *pb, int64_t pos) |
259 |
{ |
260 |
int64_t pos1; |
261 |
|
262 |
pos1 = avio_tell(pb); |
263 |
avio_seek(pb, pos + 16, SEEK_SET);
|
264 |
avio_wl64(pb, pos1 - pos); |
265 |
avio_seek(pb, pos1, SEEK_SET); |
266 |
} |
267 |
|
268 |
/* write an asf chunk (only used in streaming case) */
|
269 |
static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags) |
270 |
{ |
271 |
ASFContext *asf = s->priv_data; |
272 |
AVIOContext *pb = s->pb; |
273 |
int length;
|
274 |
|
275 |
length = payload_length + 8;
|
276 |
avio_wl16(pb, type); |
277 |
avio_wl16(pb, length); //size
|
278 |
avio_wl32(pb, asf->seqno);//sequence number
|
279 |
avio_wl16(pb, flags); /* unknown bytes */
|
280 |
avio_wl16(pb, length); //size_confirm
|
281 |
asf->seqno++; |
282 |
} |
283 |
|
284 |
/* convert from unix to windows time */
|
285 |
static int64_t unix_to_file_time(int ti) |
286 |
{ |
287 |
int64_t t; |
288 |
|
289 |
t = ti * INT64_C(10000000);
|
290 |
t += INT64_C(116444736000000000);
|
291 |
return t;
|
292 |
} |
293 |
|
294 |
/* write the header (used two times if non streamed) */
|
295 |
static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) |
296 |
{ |
297 |
ASFContext *asf = s->priv_data; |
298 |
AVIOContext *pb = s->pb; |
299 |
AVMetadataTag *tags[5];
|
300 |
int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
|
301 |
int has_title;
|
302 |
int metadata_count;
|
303 |
AVCodecContext *enc; |
304 |
int64_t header_offset, cur_pos, hpos; |
305 |
int bit_rate;
|
306 |
int64_t duration; |
307 |
|
308 |
ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
|
309 |
|
310 |
tags[0] = av_metadata_get(s->metadata, "title" , NULL, 0); |
311 |
tags[1] = av_metadata_get(s->metadata, "author" , NULL, 0); |
312 |
tags[2] = av_metadata_get(s->metadata, "copyright", NULL, 0); |
313 |
tags[3] = av_metadata_get(s->metadata, "comment" , NULL, 0); |
314 |
tags[4] = av_metadata_get(s->metadata, "rating" , NULL, 0); |
315 |
|
316 |
duration = asf->duration + PREROLL_TIME * 10000;
|
317 |
has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; |
318 |
metadata_count = s->metadata ? s->metadata->count : 0;
|
319 |
|
320 |
bit_rate = 0;
|
321 |
for(n=0;n<s->nb_streams;n++) { |
322 |
enc = s->streams[n]->codec; |
323 |
|
324 |
av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ |
325 |
|
326 |
bit_rate += enc->bit_rate; |
327 |
} |
328 |
|
329 |
if (asf->is_streamed) {
|
330 |
put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ |
331 |
} |
332 |
|
333 |
put_guid(pb, &ff_asf_header); |
334 |
avio_wl64(pb, -1); /* header length, will be patched after */ |
335 |
avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ |
336 |
avio_w8(pb, 1); /* ??? */ |
337 |
avio_w8(pb, 2); /* ??? */ |
338 |
|
339 |
/* file header */
|
340 |
header_offset = avio_tell(pb); |
341 |
hpos = put_header(pb, &ff_asf_file_header); |
342 |
put_guid(pb, &ff_asf_my_guid); |
343 |
avio_wl64(pb, file_size); |
344 |
file_time = 0;
|
345 |
avio_wl64(pb, unix_to_file_time(file_time)); |
346 |
avio_wl64(pb, asf->nb_packets); /* number of packets */
|
347 |
avio_wl64(pb, duration); /* end time stamp (in 100ns units) */
|
348 |
avio_wl64(pb, asf->duration); /* duration (in 100ns units) */
|
349 |
avio_wl64(pb, PREROLL_TIME); /* start time stamp */
|
350 |
avio_wl32(pb, (asf->is_streamed || url_is_streamed(pb)) ? 3 : 2); /* ??? */ |
351 |
avio_wl32(pb, s->packet_size); /* packet size */
|
352 |
avio_wl32(pb, s->packet_size); /* packet size */
|
353 |
avio_wl32(pb, bit_rate); /* Nominal data rate in bps */
|
354 |
end_header(pb, hpos); |
355 |
|
356 |
/* unknown headers */
|
357 |
hpos = put_header(pb, &ff_asf_head1_guid); |
358 |
put_guid(pb, &ff_asf_head2_guid); |
359 |
avio_wl32(pb, 6);
|
360 |
avio_wl16(pb, 0);
|
361 |
end_header(pb, hpos); |
362 |
|
363 |
/* title and other infos */
|
364 |
if (has_title) {
|
365 |
int len;
|
366 |
uint8_t *buf; |
367 |
AVIOContext *dyn_buf; |
368 |
|
369 |
if (url_open_dyn_buf(&dyn_buf) < 0) |
370 |
return AVERROR(ENOMEM);
|
371 |
|
372 |
hpos = put_header(pb, &ff_asf_comment_header); |
373 |
|
374 |
for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { |
375 |
len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0;
|
376 |
avio_wl16(pb, len); |
377 |
} |
378 |
len = url_close_dyn_buf(dyn_buf, &buf); |
379 |
avio_write(pb, buf, len); |
380 |
av_freep(&buf); |
381 |
end_header(pb, hpos); |
382 |
} |
383 |
if (metadata_count) {
|
384 |
AVMetadataTag *tag = NULL;
|
385 |
hpos = put_header(pb, &ff_asf_extended_content_header); |
386 |
avio_wl16(pb, metadata_count); |
387 |
while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { |
388 |
put_str16(pb, tag->key); |
389 |
avio_wl16(pb, 0);
|
390 |
put_str16(pb, tag->value); |
391 |
} |
392 |
end_header(pb, hpos); |
393 |
} |
394 |
|
395 |
/* stream headers */
|
396 |
for(n=0;n<s->nb_streams;n++) { |
397 |
int64_t es_pos; |
398 |
// ASFStream *stream = &asf->streams[n];
|
399 |
|
400 |
enc = s->streams[n]->codec; |
401 |
asf->streams[n].num = n + 1;
|
402 |
asf->streams[n].seq = 0;
|
403 |
|
404 |
|
405 |
switch(enc->codec_type) {
|
406 |
case AVMEDIA_TYPE_AUDIO:
|
407 |
wav_extra_size = 0;
|
408 |
extra_size = 18 + wav_extra_size;
|
409 |
extra_size2 = 8;
|
410 |
break;
|
411 |
default:
|
412 |
case AVMEDIA_TYPE_VIDEO:
|
413 |
wav_extra_size = enc->extradata_size; |
414 |
extra_size = 0x33 + wav_extra_size;
|
415 |
extra_size2 = 0;
|
416 |
break;
|
417 |
} |
418 |
|
419 |
hpos = put_header(pb, &ff_asf_stream_header); |
420 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
421 |
put_guid(pb, &ff_asf_audio_stream); |
422 |
put_guid(pb, &ff_asf_audio_conceal_spread); |
423 |
} else {
|
424 |
put_guid(pb, &ff_asf_video_stream); |
425 |
put_guid(pb, &ff_asf_video_conceal_none); |
426 |
} |
427 |
avio_wl64(pb, 0); /* ??? */ |
428 |
es_pos = avio_tell(pb); |
429 |
avio_wl32(pb, extra_size); /* wav header len */
|
430 |
avio_wl32(pb, extra_size2); /* additional data len */
|
431 |
avio_wl16(pb, n + 1); /* stream number */ |
432 |
avio_wl32(pb, 0); /* ??? */ |
433 |
|
434 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
435 |
/* WAVEFORMATEX header */
|
436 |
int wavsize = ff_put_wav_header(pb, enc);
|
437 |
if ((enc->codec_id != CODEC_ID_MP3) && (enc->codec_id != CODEC_ID_MP2) && (enc->codec_id != CODEC_ID_ADPCM_IMA_WAV) && (enc->extradata_size==0)) { |
438 |
wavsize += 2;
|
439 |
avio_wl16(pb, 0);
|
440 |
} |
441 |
|
442 |
if (wavsize < 0) |
443 |
return -1; |
444 |
if (wavsize != extra_size) {
|
445 |
cur_pos = avio_tell(pb); |
446 |
avio_seek(pb, es_pos, SEEK_SET); |
447 |
avio_wl32(pb, wavsize); /* wav header len */
|
448 |
avio_seek(pb, cur_pos, SEEK_SET); |
449 |
} |
450 |
/* ERROR Correction */
|
451 |
avio_w8(pb, 0x01);
|
452 |
if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){
|
453 |
avio_wl16(pb, 0x0190);
|
454 |
avio_wl16(pb, 0x0190);
|
455 |
}else{
|
456 |
avio_wl16(pb, enc->block_align); |
457 |
avio_wl16(pb, enc->block_align); |
458 |
} |
459 |
avio_wl16(pb, 0x01);
|
460 |
avio_w8(pb, 0x00);
|
461 |
} else {
|
462 |
avio_wl32(pb, enc->width); |
463 |
avio_wl32(pb, enc->height); |
464 |
avio_w8(pb, 2); /* ??? */ |
465 |
avio_wl16(pb, 40 + enc->extradata_size); /* size */ |
466 |
|
467 |
/* BITMAPINFOHEADER header */
|
468 |
ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
|
469 |
} |
470 |
end_header(pb, hpos); |
471 |
} |
472 |
|
473 |
/* media comments */
|
474 |
|
475 |
hpos = put_header(pb, &ff_asf_codec_comment_header); |
476 |
put_guid(pb, &ff_asf_codec_comment1_header); |
477 |
avio_wl32(pb, s->nb_streams); |
478 |
for(n=0;n<s->nb_streams;n++) { |
479 |
AVCodec *p; |
480 |
const char *desc; |
481 |
int len;
|
482 |
uint8_t *buf; |
483 |
AVIOContext *dyn_buf; |
484 |
|
485 |
enc = s->streams[n]->codec; |
486 |
p = avcodec_find_encoder(enc->codec_id); |
487 |
|
488 |
if(enc->codec_type == AVMEDIA_TYPE_AUDIO)
|
489 |
avio_wl16(pb, 2);
|
490 |
else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) |
491 |
avio_wl16(pb, 1);
|
492 |
else
|
493 |
avio_wl16(pb, -1);
|
494 |
|
495 |
if(enc->codec_id == CODEC_ID_WMAV2)
|
496 |
desc = "Windows Media Audio V8";
|
497 |
else
|
498 |
desc = p ? p->name : enc->codec_name; |
499 |
|
500 |
if ( url_open_dyn_buf(&dyn_buf) < 0) |
501 |
return AVERROR(ENOMEM);
|
502 |
|
503 |
avio_put_str16le(dyn_buf, desc); |
504 |
len = url_close_dyn_buf(dyn_buf, &buf); |
505 |
avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 |
506 |
|
507 |
avio_write(pb, buf, len); |
508 |
av_freep(&buf); |
509 |
|
510 |
avio_wl16(pb, 0); /* no parameters */ |
511 |
|
512 |
|
513 |
/* id */
|
514 |
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
515 |
avio_wl16(pb, 2);
|
516 |
avio_wl16(pb, enc->codec_tag); |
517 |
} else {
|
518 |
avio_wl16(pb, 4);
|
519 |
avio_wl32(pb, enc->codec_tag); |
520 |
} |
521 |
if(!enc->codec_tag)
|
522 |
return -1; |
523 |
} |
524 |
end_header(pb, hpos); |
525 |
|
526 |
/* patch the header size fields */
|
527 |
|
528 |
cur_pos = avio_tell(pb); |
529 |
header_size = cur_pos - header_offset; |
530 |
if (asf->is_streamed) {
|
531 |
header_size += 8 + 30 + 50; |
532 |
|
533 |
avio_seek(pb, header_offset - 10 - 30, SEEK_SET); |
534 |
avio_wl16(pb, header_size); |
535 |
avio_seek(pb, header_offset - 2 - 30, SEEK_SET); |
536 |
avio_wl16(pb, header_size); |
537 |
|
538 |
header_size -= 8 + 30 + 50; |
539 |
} |
540 |
header_size += 24 + 6; |
541 |
avio_seek(pb, header_offset - 14, SEEK_SET);
|
542 |
avio_wl64(pb, header_size); |
543 |
avio_seek(pb, cur_pos, SEEK_SET); |
544 |
|
545 |
/* movie chunk, followed by packets of packet_size */
|
546 |
asf->data_offset = cur_pos; |
547 |
put_guid(pb, &ff_asf_data_header); |
548 |
avio_wl64(pb, data_chunk_size); |
549 |
put_guid(pb, &ff_asf_my_guid); |
550 |
avio_wl64(pb, asf->nb_packets); /* nb packets */
|
551 |
avio_w8(pb, 1); /* ??? */ |
552 |
avio_w8(pb, 1); /* ??? */ |
553 |
return 0; |
554 |
} |
555 |
|
556 |
static int asf_write_header(AVFormatContext *s) |
557 |
{ |
558 |
ASFContext *asf = s->priv_data; |
559 |
|
560 |
s->packet_size = PACKET_SIZE; |
561 |
asf->nb_packets = 0;
|
562 |
|
563 |
asf->last_indexed_pts = 0;
|
564 |
asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK );
|
565 |
asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; |
566 |
asf->nb_index_count = 0;
|
567 |
asf->maximum_packet = 0;
|
568 |
|
569 |
/* the data-chunk-size has to be 50, which is data_size - asf->data_offset
|
570 |
* at the moment this function is done. It is needed to use asf as
|
571 |
* streamable format. */
|
572 |
if (asf_write_header1(s, 0, 50) < 0) { |
573 |
//av_free(asf);
|
574 |
return -1; |
575 |
} |
576 |
|
577 |
avio_flush(s->pb); |
578 |
|
579 |
asf->packet_nb_payloads = 0;
|
580 |
asf->packet_timestamp_start = -1;
|
581 |
asf->packet_timestamp_end = -1;
|
582 |
ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
583 |
NULL, NULL, NULL, NULL); |
584 |
|
585 |
return 0; |
586 |
} |
587 |
|
588 |
static int asf_write_stream_header(AVFormatContext *s) |
589 |
{ |
590 |
ASFContext *asf = s->priv_data; |
591 |
|
592 |
asf->is_streamed = 1;
|
593 |
|
594 |
return asf_write_header(s);
|
595 |
} |
596 |
|
597 |
static int put_payload_parsing_info( |
598 |
AVFormatContext *s, |
599 |
unsigned int sendtime, |
600 |
unsigned int duration, |
601 |
int nb_payloads,
|
602 |
int padsize
|
603 |
) |
604 |
{ |
605 |
ASFContext *asf = s->priv_data; |
606 |
AVIOContext *pb = s->pb; |
607 |
int ppi_size, i;
|
608 |
int64_t start= avio_tell(pb); |
609 |
|
610 |
int iLengthTypeFlags = ASF_PPI_LENGTH_TYPE_FLAGS;
|
611 |
|
612 |
padsize -= PACKET_HEADER_MIN_SIZE; |
613 |
if(asf->multi_payloads_present)
|
614 |
padsize--; |
615 |
assert(padsize>=0);
|
616 |
|
617 |
avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS); |
618 |
for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++){ |
619 |
avio_w8(pb, 0x0);
|
620 |
} |
621 |
|
622 |
if (asf->multi_payloads_present)
|
623 |
iLengthTypeFlags |= ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT; |
624 |
|
625 |
if (padsize > 0) { |
626 |
if (padsize < 256) |
627 |
iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE; |
628 |
else
|
629 |
iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD; |
630 |
} |
631 |
avio_w8(pb, iLengthTypeFlags); |
632 |
|
633 |
avio_w8(pb, ASF_PPI_PROPERTY_FLAGS); |
634 |
|
635 |
if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD)
|
636 |
avio_wl16(pb, padsize - 2);
|
637 |
if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE)
|
638 |
avio_w8(pb, padsize - 1);
|
639 |
|
640 |
avio_wl32(pb, sendtime); |
641 |
avio_wl16(pb, duration); |
642 |
if (asf->multi_payloads_present)
|
643 |
avio_w8(pb, nb_payloads | ASF_PAYLOAD_FLAGS); |
644 |
|
645 |
ppi_size = avio_tell(pb) - start; |
646 |
|
647 |
return ppi_size;
|
648 |
} |
649 |
|
650 |
static void flush_packet(AVFormatContext *s) |
651 |
{ |
652 |
ASFContext *asf = s->priv_data; |
653 |
int packet_hdr_size, packet_filled_size;
|
654 |
|
655 |
assert(asf->packet_timestamp_end >= asf->packet_timestamp_start); |
656 |
|
657 |
if (asf->is_streamed) {
|
658 |
put_chunk(s, 0x4424, s->packet_size, 0); |
659 |
} |
660 |
|
661 |
packet_hdr_size = put_payload_parsing_info( |
662 |
s, |
663 |
asf->packet_timestamp_start, |
664 |
asf->packet_timestamp_end - asf->packet_timestamp_start, |
665 |
asf->packet_nb_payloads, |
666 |
asf->packet_size_left |
667 |
); |
668 |
|
669 |
packet_filled_size = PACKET_SIZE - asf->packet_size_left; |
670 |
assert(packet_hdr_size <= asf->packet_size_left); |
671 |
memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
|
672 |
|
673 |
avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size); |
674 |
|
675 |
avio_flush(s->pb); |
676 |
asf->nb_packets++; |
677 |
asf->packet_nb_payloads = 0;
|
678 |
asf->packet_timestamp_start = -1;
|
679 |
asf->packet_timestamp_end = -1;
|
680 |
ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
681 |
NULL, NULL, NULL, NULL); |
682 |
} |
683 |
|
684 |
static void put_payload_header( |
685 |
AVFormatContext *s, |
686 |
ASFStream *stream, |
687 |
int presentation_time,
|
688 |
int m_obj_size,
|
689 |
int m_obj_offset,
|
690 |
int payload_len,
|
691 |
int flags
|
692 |
) |
693 |
{ |
694 |
ASFContext *asf = s->priv_data; |
695 |
AVIOContext *pb = &asf->pb; |
696 |
int val;
|
697 |
|
698 |
val = stream->num; |
699 |
if (flags & AV_PKT_FLAG_KEY)
|
700 |
val |= ASF_PL_FLAG_KEY_FRAME; |
701 |
avio_w8(pb, val); |
702 |
|
703 |
avio_w8(pb, stream->seq); //Media object number
|
704 |
avio_wl32(pb, m_obj_offset); //Offset Into Media Object
|
705 |
|
706 |
// Replicated Data shall be at least 8 bytes long.
|
707 |
// The first 4 bytes of data shall contain the
|
708 |
// Size of the Media Object that the payload belongs to.
|
709 |
// The next 4 bytes of data shall contain the
|
710 |
// Presentation Time for the media object that the payload belongs to.
|
711 |
avio_w8(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH); |
712 |
|
713 |
avio_wl32(pb, m_obj_size); //Replicated Data - Media Object Size
|
714 |
avio_wl32(pb, presentation_time);//Replicated Data - Presentation Time
|
715 |
|
716 |
if (asf->multi_payloads_present){
|
717 |
avio_wl16(pb, payload_len); //payload length
|
718 |
} |
719 |
} |
720 |
|
721 |
static void put_frame( |
722 |
AVFormatContext *s, |
723 |
ASFStream *stream, |
724 |
AVStream *avst, |
725 |
int timestamp,
|
726 |
const uint8_t *buf,
|
727 |
int m_obj_size,
|
728 |
int flags
|
729 |
) |
730 |
{ |
731 |
ASFContext *asf = s->priv_data; |
732 |
int m_obj_offset, payload_len, frag_len1;
|
733 |
|
734 |
m_obj_offset = 0;
|
735 |
while (m_obj_offset < m_obj_size) {
|
736 |
payload_len = m_obj_size - m_obj_offset; |
737 |
if (asf->packet_timestamp_start == -1) { |
738 |
asf->multi_payloads_present = (payload_len < MULTI_PAYLOAD_CONSTANT); |
739 |
|
740 |
asf->packet_size_left = PACKET_SIZE; |
741 |
if (asf->multi_payloads_present){
|
742 |
frag_len1 = MULTI_PAYLOAD_CONSTANT - 1;
|
743 |
} |
744 |
else {
|
745 |
frag_len1 = SINGLE_PAYLOAD_DATA_LENGTH; |
746 |
} |
747 |
asf->packet_timestamp_start = timestamp; |
748 |
} |
749 |
else {
|
750 |
// multi payloads
|
751 |
frag_len1 = asf->packet_size_left - PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS - PACKET_HEADER_MIN_SIZE - 1;
|
752 |
|
753 |
if(frag_len1 < payload_len && avst->codec->codec_type == AVMEDIA_TYPE_AUDIO){
|
754 |
flush_packet(s); |
755 |
continue;
|
756 |
} |
757 |
} |
758 |
if (frag_len1 > 0) { |
759 |
if (payload_len > frag_len1)
|
760 |
payload_len = frag_len1; |
761 |
else if (payload_len == (frag_len1 - 1)) |
762 |
payload_len = frag_len1 - 2; //additional byte need to put padding length |
763 |
|
764 |
put_payload_header(s, stream, timestamp+PREROLL_TIME, m_obj_size, m_obj_offset, payload_len, flags); |
765 |
avio_write(&asf->pb, buf, payload_len); |
766 |
|
767 |
if (asf->multi_payloads_present)
|
768 |
asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS); |
769 |
else
|
770 |
asf->packet_size_left -= (payload_len + PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD); |
771 |
asf->packet_timestamp_end = timestamp; |
772 |
|
773 |
asf->packet_nb_payloads++; |
774 |
} else {
|
775 |
payload_len = 0;
|
776 |
} |
777 |
m_obj_offset += payload_len; |
778 |
buf += payload_len; |
779 |
|
780 |
if (!asf->multi_payloads_present)
|
781 |
flush_packet(s); |
782 |
else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1)) |
783 |
flush_packet(s); |
784 |
} |
785 |
stream->seq++; |
786 |
} |
787 |
|
788 |
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) |
789 |
{ |
790 |
ASFContext *asf = s->priv_data; |
791 |
ASFStream *stream; |
792 |
int64_t duration; |
793 |
AVCodecContext *codec; |
794 |
int64_t packet_st,pts; |
795 |
int start_sec,i;
|
796 |
int flags= pkt->flags;
|
797 |
|
798 |
codec = s->streams[pkt->stream_index]->codec; |
799 |
stream = &asf->streams[pkt->stream_index]; |
800 |
|
801 |
if(codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
802 |
flags &= ~AV_PKT_FLAG_KEY; |
803 |
|
804 |
pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts; |
805 |
assert(pts != AV_NOPTS_VALUE); |
806 |
duration = pts * 10000;
|
807 |
asf->duration= FFMAX(asf->duration, duration + pkt->duration * 10000);
|
808 |
|
809 |
packet_st = asf->nb_packets; |
810 |
put_frame(s, stream, s->streams[pkt->stream_index], pkt->dts, pkt->data, pkt->size, flags); |
811 |
|
812 |
/* check index */
|
813 |
if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
|
814 |
start_sec = (int)(duration / INT64_C(10000000)); |
815 |
if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) { |
816 |
for(i=asf->nb_index_count;i<start_sec;i++) {
|
817 |
if (i>=asf->nb_index_memory_alloc) {
|
818 |
asf->nb_index_memory_alloc += ASF_INDEX_BLOCK; |
819 |
asf->index_ptr = (ASFIndex*)av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc );
|
820 |
} |
821 |
// store
|
822 |
asf->index_ptr[i].packet_number = (uint32_t)packet_st; |
823 |
asf->index_ptr[i].packet_count = (uint16_t)(asf->nb_packets-packet_st); |
824 |
asf->maximum_packet = FFMAX(asf->maximum_packet, (uint16_t)(asf->nb_packets-packet_st)); |
825 |
} |
826 |
asf->nb_index_count = start_sec; |
827 |
asf->last_indexed_pts = duration; |
828 |
} |
829 |
} |
830 |
return 0; |
831 |
} |
832 |
|
833 |
//
|
834 |
static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, uint32_t count) |
835 |
{ |
836 |
AVIOContext *pb = s->pb; |
837 |
int i;
|
838 |
|
839 |
put_guid(pb, &ff_asf_simple_index_header); |
840 |
avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count); |
841 |
put_guid(pb, &ff_asf_my_guid); |
842 |
avio_wl64(pb, ASF_INDEXED_INTERVAL); |
843 |
avio_wl32(pb, max); |
844 |
avio_wl32(pb, count); |
845 |
for(i=0; i<count; i++) { |
846 |
avio_wl32(pb, index[i].packet_number); |
847 |
avio_wl16(pb, index[i].packet_count); |
848 |
} |
849 |
|
850 |
return 0; |
851 |
} |
852 |
|
853 |
static int asf_write_trailer(AVFormatContext *s) |
854 |
{ |
855 |
ASFContext *asf = s->priv_data; |
856 |
int64_t file_size,data_size; |
857 |
|
858 |
/* flush the current packet */
|
859 |
if (asf->pb.buf_ptr > asf->pb.buffer)
|
860 |
flush_packet(s); |
861 |
|
862 |
/* write index */
|
863 |
data_size = avio_tell(s->pb); |
864 |
if ((!asf->is_streamed) && (asf->nb_index_count != 0)) { |
865 |
asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count); |
866 |
} |
867 |
avio_flush(s->pb); |
868 |
|
869 |
if (asf->is_streamed || url_is_streamed(s->pb)) {
|
870 |
put_chunk(s, 0x4524, 0, 0); /* end of stream */ |
871 |
} else {
|
872 |
/* rewrite an updated header */
|
873 |
file_size = avio_tell(s->pb); |
874 |
avio_seek(s->pb, 0, SEEK_SET);
|
875 |
asf_write_header1(s, file_size, data_size - asf->data_offset); |
876 |
} |
877 |
|
878 |
avio_flush(s->pb); |
879 |
av_free(asf->index_ptr); |
880 |
return 0; |
881 |
} |
882 |
|
883 |
#if CONFIG_ASF_MUXER
|
884 |
AVOutputFormat ff_asf_muxer = { |
885 |
"asf",
|
886 |
NULL_IF_CONFIG_SMALL("ASF format"),
|
887 |
"video/x-ms-asf",
|
888 |
"asf,wmv,wma",
|
889 |
sizeof(ASFContext),
|
890 |
#if CONFIG_LIBMP3LAME
|
891 |
CODEC_ID_MP3, |
892 |
#else
|
893 |
CODEC_ID_MP2, |
894 |
#endif
|
895 |
CODEC_ID_MSMPEG4V3, |
896 |
asf_write_header, |
897 |
asf_write_packet, |
898 |
asf_write_trailer, |
899 |
.flags = AVFMT_GLOBALHEADER, |
900 |
.codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
901 |
}; |
902 |
#endif
|
903 |
|
904 |
#if CONFIG_ASF_STREAM_MUXER
|
905 |
AVOutputFormat ff_asf_stream_muxer = { |
906 |
"asf_stream",
|
907 |
NULL_IF_CONFIG_SMALL("ASF format"),
|
908 |
"video/x-ms-asf",
|
909 |
"asf,wmv,wma",
|
910 |
sizeof(ASFContext),
|
911 |
#if CONFIG_LIBMP3LAME
|
912 |
CODEC_ID_MP3, |
913 |
#else
|
914 |
CODEC_ID_MP2, |
915 |
#endif
|
916 |
CODEC_ID_MSMPEG4V3, |
917 |
asf_write_stream_header, |
918 |
asf_write_packet, |
919 |
asf_write_trailer, |
920 |
.flags = AVFMT_GLOBALHEADER, |
921 |
.codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
922 |
}; |
923 |
#endif //CONFIG_ASF_STREAM_MUXER |