ffmpeg / libavformat / asfenc.c @ e731b8d8
History | View | Annotate | Download (30.4 KB)
1 | 542993b0 | Konstantin Andreyev | /*
|
---|---|---|---|
2 | f26be477 | Michael Niedermayer | * ASF muxer
|
3 | 406792e7 | Diego Biurrun | * Copyright (c) 2000, 2001 Fabrice Bellard
|
4 | 542993b0 | Konstantin Andreyev | *
|
5 | b78e7197 | Diego Biurrun | * This file is part of FFmpeg.
|
6 | *
|
||
7 | * FFmpeg is free software; you can redistribute it and/or
|
||
8 | 542993b0 | Konstantin Andreyev | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
11 | 542993b0 | Konstantin Andreyev | *
|
12 | b78e7197 | Diego Biurrun | * FFmpeg is distributed in the hope that it will be useful,
|
13 | 542993b0 | Konstantin Andreyev | * 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 | b78e7197 | Diego Biurrun | * License along with FFmpeg; if not, write to the Free Software
|
19 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | 542993b0 | Konstantin Andreyev | */
|
21 | #include "avformat.h" |
||
22 | 488227c5 | Aurelien Jacobs | #include "metadata.h" |
23 | 9d9f4119 | Måns Rullgård | #include "riff.h" |
24 | 542993b0 | Konstantin Andreyev | #include "asf.h" |
25 | e731b8d8 | Anton Khirnov | #include "avio_internal.h" |
26 | 542993b0 | Konstantin Andreyev | |
27 | #undef NDEBUG
|
||
28 | #include <assert.h> |
||
29 | |||
30 | 982e53fe | Calcium | |
31 | bb270c08 | Diego Biurrun | #define ASF_INDEXED_INTERVAL 10000000 |
32 | #define ASF_INDEX_BLOCK 600 |
||
33 | 982e53fe | Calcium | |
34 | 615b92fd | Konstantin Andreyev | #define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2 |
35 | #define ASF_PACKET_ERROR_CORRECTION_FLAGS (\
|
||
36 | bb270c08 | Diego Biurrun | ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT | \ |
37 | ASF_PACKET_ERROR_CORRECTION_DATA_SIZE\ |
||
38 | ) |
||
39 | 615b92fd | Konstantin Andreyev | |
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 | bb270c08 | Diego Biurrun | 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 | 615b92fd | Konstantin Andreyev | |
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 | bb270c08 | Diego Biurrun | 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 | 615b92fd | Konstantin Andreyev | |
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 | bb270c08 | Diego Biurrun | 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 | 115329f1 | Diego Biurrun | |
170 | 615b92fd | Konstantin Andreyev | #define PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS (\
|
171 | bb270c08 | Diego Biurrun | 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 | 615b92fd | Konstantin Andreyev | |
179 | #define SINGLE_PAYLOAD_DATA_LENGTH (\
|
||
180 | bb270c08 | Diego Biurrun | PACKET_SIZE - \ |
181 | PACKET_HEADER_MIN_SIZE - \ |
||
182 | PAYLOAD_HEADER_SIZE_SINGLE_PAYLOAD \ |
||
183 | ) |
||
184 | 615b92fd | Konstantin Andreyev | |
185 | #define MULTI_PAYLOAD_CONSTANT (\
|
||
186 | bb270c08 | Diego Biurrun | PACKET_SIZE - \ |
187 | PACKET_HEADER_MIN_SIZE - \ |
||
188 | 1 - /*Payload Flags*/ \ |
||
189 | 2*PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS \
|
||
190 | ) |
||
191 | 615b92fd | Konstantin Andreyev | |
192 | 4bc328a2 | Anton Khirnov | 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 | ae628ec1 | Anton Khirnov | AVIOContext pb; |
207 | 4bc328a2 | Anton Khirnov | /* 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 | 7caf0cc6 | Michael Niedermayer | 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 | 3caa0d93 | Alex Beregszaszi | #define PREROLL_TIME 3100 |
225 | 615b92fd | Konstantin Andreyev | |
226 | ae628ec1 | Anton Khirnov | static void put_guid(AVIOContext *s, const ff_asf_guid *g) |
227 | 542993b0 | Konstantin Andreyev | { |
228 | 24c14d6d | Michael Niedermayer | assert(sizeof(*g) == 16); |
229 | d7742a74 | Baptiste Coudurier | put_buffer(s, *g, sizeof(*g));
|
230 | 542993b0 | Konstantin Andreyev | } |
231 | |||
232 | ae628ec1 | Anton Khirnov | static void put_str16(AVIOContext *s, const char *tag) |
233 | cba2f6d5 | Anton Khirnov | { |
234 | int len;
|
||
235 | uint8_t *pb; |
||
236 | ae628ec1 | Anton Khirnov | AVIOContext *dyn_buf; |
237 | cba2f6d5 | Anton Khirnov | if (url_open_dyn_buf(&dyn_buf) < 0) |
238 | return;
|
||
239 | |||
240 | dccbd97d | Anton Khirnov | avio_put_str16le(dyn_buf, tag); |
241 | cba2f6d5 | Anton Khirnov | len = url_close_dyn_buf(dyn_buf, &pb); |
242 | put_le16(s, len); |
||
243 | put_buffer(s, pb, len); |
||
244 | av_freep(&pb); |
||
245 | 542993b0 | Konstantin Andreyev | } |
246 | |||
247 | ae628ec1 | Anton Khirnov | static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g) |
248 | 542993b0 | Konstantin Andreyev | { |
249 | int64_t pos; |
||
250 | |||
251 | pos = url_ftell(pb); |
||
252 | put_guid(pb, g); |
||
253 | put_le64(pb, 24);
|
||
254 | return pos;
|
||
255 | } |
||
256 | |||
257 | /* update header size */
|
||
258 | ae628ec1 | Anton Khirnov | static void end_header(AVIOContext *pb, int64_t pos) |
259 | 542993b0 | Konstantin Andreyev | { |
260 | int64_t pos1; |
||
261 | |||
262 | pos1 = url_ftell(pb); |
||
263 | url_fseek(pb, pos + 16, SEEK_SET);
|
||
264 | put_le64(pb, pos1 - pos); |
||
265 | url_fseek(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 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
273 | 542993b0 | Konstantin Andreyev | int length;
|
274 | |||
275 | length = payload_length + 8;
|
||
276 | put_le16(pb, type); |
||
277 | 615b92fd | Konstantin Andreyev | put_le16(pb, length); //size
|
278 | put_le32(pb, asf->seqno);//sequence number
|
||
279 | 542993b0 | Konstantin Andreyev | put_le16(pb, flags); /* unknown bytes */
|
280 | 615b92fd | Konstantin Andreyev | put_le16(pb, length); //size_confirm
|
281 | 542993b0 | Konstantin Andreyev | 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 | 8da9266c | Måns Rullgård | t = ti * INT64_C(10000000);
|
290 | t += INT64_C(116444736000000000);
|
||
291 | 542993b0 | Konstantin Andreyev | 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 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
299 | a677078e | Anton Khirnov | AVMetadataTag *tags[5];
|
300 | 542993b0 | Konstantin Andreyev | int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
|
301 | int has_title;
|
||
302 | 488227c5 | Aurelien Jacobs | int metadata_count;
|
303 | 542993b0 | Konstantin Andreyev | AVCodecContext *enc; |
304 | int64_t header_offset, cur_pos, hpos; |
||
305 | int bit_rate;
|
||
306 | 4336886c | Brian Brice | int64_t duration; |
307 | 542993b0 | Konstantin Andreyev | |
308 | ad7768f4 | Anton Khirnov | ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
|
309 | 03700d39 | Anton Khirnov | |
310 | a677078e | Anton Khirnov | 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 | 300f24f3 | Aurelien Jacobs | |
316 | 3caa0d93 | Alex Beregszaszi | duration = asf->duration + PREROLL_TIME * 10000;
|
317 | a677078e | Anton Khirnov | has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; |
318 | 488227c5 | Aurelien Jacobs | metadata_count = s->metadata ? s->metadata->count : 0;
|
319 | 542993b0 | Konstantin Andreyev | |
320 | bit_rate = 0;
|
||
321 | for(n=0;n<s->nb_streams;n++) { |
||
322 | 01f4895c | Michael Niedermayer | enc = s->streams[n]->codec; |
323 | 542993b0 | Konstantin Andreyev | |
324 | 9ee91c2f | Michael Niedermayer | av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ |
325 | |||
326 | 542993b0 | Konstantin Andreyev | 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 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_header); |
334 | 542993b0 | Konstantin Andreyev | put_le64(pb, -1); /* header length, will be patched after */ |
335 | 488227c5 | Aurelien Jacobs | put_le32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ |
336 | 542993b0 | Konstantin Andreyev | put_byte(pb, 1); /* ??? */ |
337 | put_byte(pb, 2); /* ??? */ |
||
338 | |||
339 | /* file header */
|
||
340 | header_offset = url_ftell(pb); |
||
341 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_file_header); |
342 | put_guid(pb, &ff_asf_my_guid); |
||
343 | 542993b0 | Konstantin Andreyev | put_le64(pb, file_size); |
344 | file_time = 0;
|
||
345 | put_le64(pb, unix_to_file_time(file_time)); |
||
346 | put_le64(pb, asf->nb_packets); /* number of packets */
|
||
347 | 4336886c | Brian Brice | put_le64(pb, duration); /* end time stamp (in 100ns units) */
|
348 | 737287f8 | Michael Niedermayer | put_le64(pb, asf->duration); /* duration (in 100ns units) */
|
349 | 3caa0d93 | Alex Beregszaszi | put_le64(pb, PREROLL_TIME); /* start time stamp */
|
350 | e1315fb1 | Michael Niedermayer | put_le32(pb, (asf->is_streamed || url_is_streamed(pb)) ? 3 : 2); /* ??? */ |
351 | 91d19d47 | Ronald S. Bultje | put_le32(pb, s->packet_size); /* packet size */
|
352 | put_le32(pb, s->packet_size); /* packet size */
|
||
353 | 542993b0 | Konstantin Andreyev | put_le32(pb, bit_rate); /* Nominal data rate in bps */
|
354 | end_header(pb, hpos); |
||
355 | |||
356 | /* unknown headers */
|
||
357 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_head1_guid); |
358 | put_guid(pb, &ff_asf_head2_guid); |
||
359 | 542993b0 | Konstantin Andreyev | put_le32(pb, 6);
|
360 | put_le16(pb, 0);
|
||
361 | end_header(pb, hpos); |
||
362 | |||
363 | /* title and other infos */
|
||
364 | if (has_title) {
|
||
365 | cba2f6d5 | Anton Khirnov | int len;
|
366 | uint8_t *buf; |
||
367 | ae628ec1 | Anton Khirnov | AVIOContext *dyn_buf; |
368 | cba2f6d5 | Anton Khirnov | |
369 | if (url_open_dyn_buf(&dyn_buf) < 0) |
||
370 | return AVERROR(ENOMEM);
|
||
371 | |||
372 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_comment_header); |
373 | cba2f6d5 | Anton Khirnov | |
374 | for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { |
||
375 | dccbd97d | Anton Khirnov | len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0;
|
376 | cba2f6d5 | Anton Khirnov | put_le16(pb, len); |
377 | } |
||
378 | len = url_close_dyn_buf(dyn_buf, &buf); |
||
379 | put_buffer(pb, buf, len); |
||
380 | av_freep(&buf); |
||
381 | 542993b0 | Konstantin Andreyev | end_header(pb, hpos); |
382 | } |
||
383 | 488227c5 | Aurelien Jacobs | if (metadata_count) {
|
384 | AVMetadataTag *tag = NULL;
|
||
385 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_extended_content_header); |
386 | 488227c5 | Aurelien Jacobs | put_le16(pb, metadata_count); |
387 | while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { |
||
388 | cba2f6d5 | Anton Khirnov | put_str16(pb, tag->key); |
389 | 488227c5 | Aurelien Jacobs | put_le16(pb, 0);
|
390 | cba2f6d5 | Anton Khirnov | put_str16(pb, tag->value); |
391 | 488227c5 | Aurelien Jacobs | } |
392 | end_header(pb, hpos); |
||
393 | } |
||
394 | 542993b0 | Konstantin Andreyev | |
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 | 01f4895c | Michael Niedermayer | enc = s->streams[n]->codec; |
401 | 542993b0 | Konstantin Andreyev | asf->streams[n].num = n + 1;
|
402 | asf->streams[n].seq = 0;
|
||
403 | |||
404 | 115329f1 | Diego Biurrun | |
405 | 542993b0 | Konstantin Andreyev | switch(enc->codec_type) {
|
406 | 72415b2a | Stefano Sabatini | case AVMEDIA_TYPE_AUDIO:
|
407 | 542993b0 | Konstantin Andreyev | wav_extra_size = 0;
|
408 | extra_size = 18 + wav_extra_size;
|
||
409 | 1d7d9935 | Michael Niedermayer | extra_size2 = 8;
|
410 | 542993b0 | Konstantin Andreyev | break;
|
411 | default:
|
||
412 | 72415b2a | Stefano Sabatini | case AVMEDIA_TYPE_VIDEO:
|
413 | 982e53fe | Calcium | wav_extra_size = enc->extradata_size; |
414 | extra_size = 0x33 + wav_extra_size;
|
||
415 | 542993b0 | Konstantin Andreyev | extra_size2 = 0;
|
416 | break;
|
||
417 | } |
||
418 | |||
419 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_stream_header); |
420 | 72415b2a | Stefano Sabatini | if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
421 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_audio_stream); |
422 | put_guid(pb, &ff_asf_audio_conceal_spread); |
||
423 | 542993b0 | Konstantin Andreyev | } else {
|
424 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_video_stream); |
425 | put_guid(pb, &ff_asf_video_conceal_none); |
||
426 | 542993b0 | Konstantin Andreyev | } |
427 | put_le64(pb, 0); /* ??? */ |
||
428 | es_pos = url_ftell(pb); |
||
429 | put_le32(pb, extra_size); /* wav header len */
|
||
430 | put_le32(pb, extra_size2); /* additional data len */
|
||
431 | put_le16(pb, n + 1); /* stream number */ |
||
432 | put_le32(pb, 0); /* ??? */ |
||
433 | |||
434 | 72415b2a | Stefano Sabatini | if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
435 | 542993b0 | Konstantin Andreyev | /* WAVEFORMATEX header */
|
436 | 1a40491e | Daniel Verkamp | int wavsize = ff_put_wav_header(pb, enc);
|
437 | 982e53fe | Calcium | 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 | put_le16(pb, 0);
|
||
440 | } |
||
441 | 542993b0 | Konstantin Andreyev | |
442 | if (wavsize < 0) |
||
443 | return -1; |
||
444 | if (wavsize != extra_size) {
|
||
445 | cur_pos = url_ftell(pb); |
||
446 | url_fseek(pb, es_pos, SEEK_SET); |
||
447 | put_le32(pb, wavsize); /* wav header len */
|
||
448 | url_fseek(pb, cur_pos, SEEK_SET); |
||
449 | } |
||
450 | 982e53fe | Calcium | /* ERROR Correction */
|
451 | 1d7d9935 | Michael Niedermayer | put_byte(pb, 0x01);
|
452 | if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){
|
||
453 | put_le16(pb, 0x0190);
|
||
454 | put_le16(pb, 0x0190);
|
||
455 | }else{
|
||
456 | put_le16(pb, enc->block_align); |
||
457 | put_le16(pb, enc->block_align); |
||
458 | } |
||
459 | put_le16(pb, 0x01);
|
||
460 | put_byte(pb, 0x00);
|
||
461 | 542993b0 | Konstantin Andreyev | } else {
|
462 | put_le32(pb, enc->width); |
||
463 | put_le32(pb, enc->height); |
||
464 | put_byte(pb, 2); /* ??? */ |
||
465 | 982e53fe | Calcium | put_le16(pb, 40 + enc->extradata_size); /* size */ |
466 | 542993b0 | Konstantin Andreyev | |
467 | /* BITMAPINFOHEADER header */
|
||
468 | 1a40491e | Daniel Verkamp | ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
|
469 | 542993b0 | Konstantin Andreyev | } |
470 | end_header(pb, hpos); |
||
471 | } |
||
472 | |||
473 | /* media comments */
|
||
474 | |||
475 | 17af0525 | Aurelien Jacobs | hpos = put_header(pb, &ff_asf_codec_comment_header); |
476 | put_guid(pb, &ff_asf_codec_comment1_header); |
||
477 | 542993b0 | Konstantin Andreyev | put_le32(pb, s->nb_streams); |
478 | for(n=0;n<s->nb_streams;n++) { |
||
479 | AVCodec *p; |
||
480 | 531d8fa3 | Anton Khirnov | const char *desc; |
481 | cba2f6d5 | Anton Khirnov | int len;
|
482 | uint8_t *buf; |
||
483 | ae628ec1 | Anton Khirnov | AVIOContext *dyn_buf; |
484 | 542993b0 | Konstantin Andreyev | |
485 | 01f4895c | Michael Niedermayer | enc = s->streams[n]->codec; |
486 | 542993b0 | Konstantin Andreyev | p = avcodec_find_encoder(enc->codec_id); |
487 | |||
488 | 72415b2a | Stefano Sabatini | if(enc->codec_type == AVMEDIA_TYPE_AUDIO)
|
489 | 7205395b | Michael Niedermayer | put_le16(pb, 2);
|
490 | 72415b2a | Stefano Sabatini | else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) |
491 | 7205395b | Michael Niedermayer | put_le16(pb, 1);
|
492 | else
|
||
493 | put_le16(pb, -1);
|
||
494 | |||
495 | if(enc->codec_id == CODEC_ID_WMAV2)
|
||
496 | 531d8fa3 | Anton Khirnov | desc = "Windows Media Audio V8";
|
497 | 7205395b | Michael Niedermayer | else
|
498 | 531d8fa3 | Anton Khirnov | desc = p ? p->name : enc->codec_name; |
499 | cba2f6d5 | Anton Khirnov | |
500 | if ( url_open_dyn_buf(&dyn_buf) < 0) |
||
501 | return AVERROR(ENOMEM);
|
||
502 | |||
503 | dccbd97d | Anton Khirnov | avio_put_str16le(dyn_buf, desc); |
504 | cba2f6d5 | Anton Khirnov | len = url_close_dyn_buf(dyn_buf, &buf); |
505 | put_le16(pb, len / 2); // "number of characters" = length in bytes / 2 |
||
506 | |||
507 | put_buffer(pb, buf, len); |
||
508 | av_freep(&buf); |
||
509 | |||
510 | 542993b0 | Konstantin Andreyev | put_le16(pb, 0); /* no parameters */ |
511 | 115329f1 | Diego Biurrun | |
512 | |||
513 | 542993b0 | Konstantin Andreyev | /* id */
|
514 | 72415b2a | Stefano Sabatini | if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
|
515 | 542993b0 | Konstantin Andreyev | put_le16(pb, 2);
|
516 | put_le16(pb, enc->codec_tag); |
||
517 | } else {
|
||
518 | put_le16(pb, 4);
|
||
519 | put_le32(pb, enc->codec_tag); |
||
520 | } |
||
521 | d65b8230 | Michael Niedermayer | if(!enc->codec_tag)
|
522 | return -1; |
||
523 | 542993b0 | Konstantin Andreyev | } |
524 | end_header(pb, hpos); |
||
525 | |||
526 | /* patch the header size fields */
|
||
527 | |||
528 | cur_pos = url_ftell(pb); |
||
529 | header_size = cur_pos - header_offset; |
||
530 | if (asf->is_streamed) {
|
||
531 | header_size += 8 + 30 + 50; |
||
532 | |||
533 | url_fseek(pb, header_offset - 10 - 30, SEEK_SET); |
||
534 | put_le16(pb, header_size); |
||
535 | url_fseek(pb, header_offset - 2 - 30, SEEK_SET); |
||
536 | put_le16(pb, header_size); |
||
537 | |||
538 | header_size -= 8 + 30 + 50; |
||
539 | } |
||
540 | header_size += 24 + 6; |
||
541 | url_fseek(pb, header_offset - 14, SEEK_SET);
|
||
542 | put_le64(pb, header_size); |
||
543 | url_fseek(pb, cur_pos, SEEK_SET); |
||
544 | |||
545 | /* movie chunk, followed by packets of packet_size */
|
||
546 | asf->data_offset = cur_pos; |
||
547 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_data_header); |
548 | 542993b0 | Konstantin Andreyev | put_le64(pb, data_chunk_size); |
549 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_my_guid); |
550 | 542993b0 | Konstantin Andreyev | put_le64(pb, asf->nb_packets); /* nb packets */
|
551 | put_byte(pb, 1); /* ??? */ |
||
552 | put_byte(pb, 1); /* ??? */ |
||
553 | return 0; |
||
554 | } |
||
555 | |||
556 | static int asf_write_header(AVFormatContext *s) |
||
557 | { |
||
558 | ASFContext *asf = s->priv_data; |
||
559 | |||
560 | 91d19d47 | Ronald S. Bultje | s->packet_size = PACKET_SIZE; |
561 | 542993b0 | Konstantin Andreyev | asf->nb_packets = 0;
|
562 | 115329f1 | Diego Biurrun | |
563 | 982e53fe | Calcium | asf->last_indexed_pts = 0;
|
564 | 90901860 | Michael Niedermayer | asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK );
|
565 | 982e53fe | Calcium | asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; |
566 | asf->nb_index_count = 0;
|
||
567 | asf->maximum_packet = 0;
|
||
568 | 542993b0 | Konstantin Andreyev | |
569 | ed7b48b2 | Patric Stout | /* 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 | 542993b0 | Konstantin Andreyev | //av_free(asf);
|
574 | return -1; |
||
575 | } |
||
576 | |||
577 | 899681cd | Björn Axelsson | put_flush_packet(s->pb); |
578 | 542993b0 | Konstantin Andreyev | |
579 | 615b92fd | Konstantin Andreyev | asf->packet_nb_payloads = 0;
|
580 | 542993b0 | Konstantin Andreyev | asf->packet_timestamp_start = -1;
|
581 | asf->packet_timestamp_end = -1;
|
||
582 | e731b8d8 | Anton Khirnov | ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
583 | 542993b0 | Konstantin Andreyev | 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 | 615b92fd | Konstantin Andreyev | static int put_payload_parsing_info( |
598 | AVFormatContext *s, |
||
599 | 115329f1 | Diego Biurrun | unsigned int sendtime, |
600 | 615b92fd | Konstantin Andreyev | unsigned int duration, |
601 | 115329f1 | Diego Biurrun | int nb_payloads,
|
602 | 615b92fd | Konstantin Andreyev | int padsize
|
603 | ) |
||
604 | 542993b0 | Konstantin Andreyev | { |
605 | ASFContext *asf = s->priv_data; |
||
606 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
607 | 615b92fd | Konstantin Andreyev | int ppi_size, i;
|
608 | ff5b8d83 | Michael Niedermayer | int64_t start= url_ftell(pb); |
609 | 615b92fd | Konstantin Andreyev | |
610 | int iLengthTypeFlags = ASF_PPI_LENGTH_TYPE_FLAGS;
|
||
611 | 115329f1 | Diego Biurrun | |
612 | 2d241e66 | Michael Niedermayer | padsize -= PACKET_HEADER_MIN_SIZE; |
613 | if(asf->multi_payloads_present)
|
||
614 | padsize--; |
||
615 | assert(padsize>=0);
|
||
616 | |||
617 | 615b92fd | Konstantin Andreyev | put_byte(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS); |
618 | for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++){ |
||
619 | put_byte(pb, 0x0);
|
||
620 | 542993b0 | Konstantin Andreyev | } |
621 | |||
622 | 615b92fd | Konstantin Andreyev | if (asf->multi_payloads_present)
|
623 | iLengthTypeFlags |= ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT; |
||
624 | 542993b0 | Konstantin Andreyev | |
625 | if (padsize > 0) { |
||
626 | if (padsize < 256) |
||
627 | 615b92fd | Konstantin Andreyev | iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE; |
628 | 542993b0 | Konstantin Andreyev | else
|
629 | 615b92fd | Konstantin Andreyev | iLengthTypeFlags |= ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD; |
630 | 542993b0 | Konstantin Andreyev | } |
631 | 615b92fd | Konstantin Andreyev | put_byte(pb, iLengthTypeFlags); |
632 | |||
633 | put_byte(pb, ASF_PPI_PROPERTY_FLAGS); |
||
634 | |||
635 | if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD)
|
||
636 | 542993b0 | Konstantin Andreyev | put_le16(pb, padsize - 2);
|
637 | 615b92fd | Konstantin Andreyev | if (iLengthTypeFlags & ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE)
|
638 | 542993b0 | Konstantin Andreyev | put_byte(pb, padsize - 1);
|
639 | 615b92fd | Konstantin Andreyev | |
640 | put_le32(pb, sendtime); |
||
641 | 542993b0 | Konstantin Andreyev | put_le16(pb, duration); |
642 | 615b92fd | Konstantin Andreyev | if (asf->multi_payloads_present)
|
643 | put_byte(pb, nb_payloads | ASF_PAYLOAD_FLAGS); |
||
644 | |||
645 | ff5b8d83 | Michael Niedermayer | ppi_size = url_ftell(pb) - start; |
646 | 542993b0 | Konstantin Andreyev | |
647 | 615b92fd | Konstantin Andreyev | return ppi_size;
|
648 | 542993b0 | Konstantin Andreyev | } |
649 | |||
650 | static void flush_packet(AVFormatContext *s) |
||
651 | { |
||
652 | ASFContext *asf = s->priv_data; |
||
653 | 615b92fd | Konstantin Andreyev | int packet_hdr_size, packet_filled_size;
|
654 | 542993b0 | Konstantin Andreyev | |
655 | a57c41b2 | Michael Niedermayer | assert(asf->packet_timestamp_end >= asf->packet_timestamp_start); |
656 | |||
657 | 615b92fd | Konstantin Andreyev | if (asf->is_streamed) {
|
658 | 91d19d47 | Ronald S. Bultje | put_chunk(s, 0x4424, s->packet_size, 0); |
659 | 615b92fd | Konstantin Andreyev | } |
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 | 542993b0 | Konstantin Andreyev | |
669 | 2d241e66 | Michael Niedermayer | packet_filled_size = PACKET_SIZE - asf->packet_size_left; |
670 | assert(packet_hdr_size <= asf->packet_size_left); |
||
671 | 615b92fd | Konstantin Andreyev | memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
|
672 | 542993b0 | Konstantin Andreyev | |
673 | 91d19d47 | Ronald S. Bultje | put_buffer(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size); |
674 | 542993b0 | Konstantin Andreyev | |
675 | 899681cd | Björn Axelsson | put_flush_packet(s->pb); |
676 | 542993b0 | Konstantin Andreyev | asf->nb_packets++; |
677 | 615b92fd | Konstantin Andreyev | asf->packet_nb_payloads = 0;
|
678 | 542993b0 | Konstantin Andreyev | asf->packet_timestamp_start = -1;
|
679 | asf->packet_timestamp_end = -1;
|
||
680 | e731b8d8 | Anton Khirnov | ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
|
681 | 542993b0 | Konstantin Andreyev | NULL, NULL, NULL, NULL); |
682 | } |
||
683 | |||
684 | 615b92fd | Konstantin Andreyev | 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 | 3c895fc0 | Michael Niedermayer | int payload_len,
|
691 | int flags
|
||
692 | 615b92fd | Konstantin Andreyev | ) |
693 | 542993b0 | Konstantin Andreyev | { |
694 | ASFContext *asf = s->priv_data; |
||
695 | ae628ec1 | Anton Khirnov | AVIOContext *pb = &asf->pb; |
696 | 542993b0 | Konstantin Andreyev | int val;
|
697 | 115329f1 | Diego Biurrun | |
698 | 542993b0 | Konstantin Andreyev | val = stream->num; |
699 | cc947f04 | Jean-Daniel Dupas | if (flags & AV_PKT_FLAG_KEY)
|
700 | 615b92fd | Konstantin Andreyev | val |= ASF_PL_FLAG_KEY_FRAME; |
701 | 542993b0 | Konstantin Andreyev | put_byte(pb, val); |
702 | 115329f1 | Diego Biurrun | |
703 | 615b92fd | Konstantin Andreyev | put_byte(pb, stream->seq); //Media object number
|
704 | put_le32(pb, m_obj_offset); //Offset Into Media Object
|
||
705 | 115329f1 | Diego Biurrun | |
706 | 615b92fd | Konstantin Andreyev | // Replicated Data shall be at least 8 bytes long.
|
707 | 115329f1 | Diego Biurrun | // The first 4 bytes of data shall contain the
|
708 | 615b92fd | Konstantin Andreyev | // Size of the Media Object that the payload belongs to.
|
709 | 115329f1 | Diego Biurrun | // The next 4 bytes of data shall contain the
|
710 | 615b92fd | Konstantin Andreyev | // Presentation Time for the media object that the payload belongs to.
|
711 | put_byte(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH); |
||
712 | |||
713 | put_le32(pb, m_obj_size); //Replicated Data - Media Object Size
|
||
714 | put_le32(pb, presentation_time);//Replicated Data - Presentation Time
|
||
715 | 115329f1 | Diego Biurrun | |
716 | 615b92fd | Konstantin Andreyev | if (asf->multi_payloads_present){
|
717 | put_le16(pb, payload_len); //payload length
|
||
718 | } |
||
719 | 542993b0 | Konstantin Andreyev | } |
720 | |||
721 | 615b92fd | Konstantin Andreyev | static void put_frame( |
722 | AVFormatContext *s, |
||
723 | ASFStream *stream, |
||
724 | 75b213ed | Michael Niedermayer | AVStream *avst, |
725 | bb270c08 | Diego Biurrun | int timestamp,
|
726 | 615b92fd | Konstantin Andreyev | const uint8_t *buf,
|
727 | bb270c08 | Diego Biurrun | int m_obj_size,
|
728 | 3c895fc0 | Michael Niedermayer | int flags
|
729 | bb270c08 | Diego Biurrun | ) |
730 | 542993b0 | Konstantin Andreyev | { |
731 | ASFContext *asf = s->priv_data; |
||
732 | 615b92fd | Konstantin Andreyev | 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 | 115329f1 | Diego Biurrun | |
740 | 2d241e66 | Michael Niedermayer | asf->packet_size_left = PACKET_SIZE; |
741 | 615b92fd | Konstantin Andreyev | if (asf->multi_payloads_present){
|
742 | frag_len1 = MULTI_PAYLOAD_CONSTANT - 1;
|
||
743 | } |
||
744 | else {
|
||
745 | frag_len1 = SINGLE_PAYLOAD_DATA_LENGTH; |
||
746 | } |
||
747 | 190972a0 | Michael Niedermayer | asf->packet_timestamp_start = timestamp; |
748 | 615b92fd | Konstantin Andreyev | } |
749 | else {
|
||
750 | // multi payloads
|
||
751 | 2d241e66 | Michael Niedermayer | frag_len1 = asf->packet_size_left - PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS - PACKET_HEADER_MIN_SIZE - 1;
|
752 | 542993b0 | Konstantin Andreyev | |
753 | 72415b2a | Stefano Sabatini | if(frag_len1 < payload_len && avst->codec->codec_type == AVMEDIA_TYPE_AUDIO){
|
754 | 75b213ed | Michael Niedermayer | flush_packet(s); |
755 | continue;
|
||
756 | } |
||
757 | 615b92fd | Konstantin Andreyev | } |
758 | 542993b0 | Konstantin Andreyev | if (frag_len1 > 0) { |
759 | 615b92fd | Konstantin Andreyev | 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 | 115329f1 | Diego Biurrun | |
764 | 3caa0d93 | Alex Beregszaszi | put_payload_header(s, stream, timestamp+PREROLL_TIME, m_obj_size, m_obj_offset, payload_len, flags); |
765 | 615b92fd | Konstantin Andreyev | put_buffer(&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 | 542993b0 | Konstantin Andreyev | asf->packet_timestamp_end = timestamp; |
772 | 115329f1 | Diego Biurrun | |
773 | 615b92fd | Konstantin Andreyev | asf->packet_nb_payloads++; |
774 | 542993b0 | Konstantin Andreyev | } else {
|
775 | 615b92fd | Konstantin Andreyev | payload_len = 0;
|
776 | 542993b0 | Konstantin Andreyev | } |
777 | 615b92fd | Konstantin Andreyev | m_obj_offset += payload_len; |
778 | buf += payload_len; |
||
779 | |||
780 | if (!asf->multi_payloads_present)
|
||
781 | flush_packet(s); |
||
782 | 2d241e66 | Michael Niedermayer | else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1)) |
783 | 542993b0 | Konstantin Andreyev | flush_packet(s); |
784 | } |
||
785 | stream->seq++; |
||
786 | } |
||
787 | |||
788 | e928649b | Michael Niedermayer | static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) |
789 | 542993b0 | Konstantin Andreyev | { |
790 | ASFContext *asf = s->priv_data; |
||
791 | ASFStream *stream; |
||
792 | int64_t duration; |
||
793 | AVCodecContext *codec; |
||
794 | 115329f1 | Diego Biurrun | int64_t packet_st,pts; |
795 | 982e53fe | Calcium | int start_sec,i;
|
796 | 0d9f8633 | Michael Niedermayer | int flags= pkt->flags;
|
797 | 542993b0 | Konstantin Andreyev | |
798 | 01f4895c | Michael Niedermayer | codec = s->streams[pkt->stream_index]->codec; |
799 | e928649b | Michael Niedermayer | stream = &asf->streams[pkt->stream_index]; |
800 | 542993b0 | Konstantin Andreyev | |
801 | 72415b2a | Stefano Sabatini | if(codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
802 | cc947f04 | Jean-Daniel Dupas | flags &= ~AV_PKT_FLAG_KEY; |
803 | 0d9f8633 | Michael Niedermayer | |
804 | 982e53fe | Calcium | pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts; |
805 | 9bc93229 | Michael Niedermayer | assert(pts != AV_NOPTS_VALUE); |
806 | duration = pts * 10000;
|
||
807 | 4fa6eac5 | Henrik Gulbrandsen | asf->duration= FFMAX(asf->duration, duration + pkt->duration * 10000);
|
808 | 542993b0 | Konstantin Andreyev | |
809 | 982e53fe | Calcium | packet_st = asf->nb_packets; |
810 | 75b213ed | Michael Niedermayer | put_frame(s, stream, s->streams[pkt->stream_index], pkt->dts, pkt->data, pkt->size, flags); |
811 | 982e53fe | Calcium | |
812 | /* check index */
|
||
813 | cc947f04 | Jean-Daniel Dupas | if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
|
814 | 8da9266c | Måns Rullgård | start_sec = (int)(duration / INT64_C(10000000)); |
815 | if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) { |
||
816 | 982e53fe | Calcium | 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 | d65b8230 | Michael Niedermayer | asf->maximum_packet = FFMAX(asf->maximum_packet, (uint16_t)(asf->nb_packets-packet_st)); |
825 | 982e53fe | Calcium | } |
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 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
837 | 982e53fe | Calcium | int i;
|
838 | |||
839 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_simple_index_header); |
840 | 982e53fe | Calcium | put_le64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count); |
841 | 17af0525 | Aurelien Jacobs | put_guid(pb, &ff_asf_my_guid); |
842 | 982e53fe | Calcium | put_le64(pb, ASF_INDEXED_INTERVAL); |
843 | put_le32(pb, max); |
||
844 | put_le32(pb, count); |
||
845 | for(i=0; i<count; i++) { |
||
846 | put_le32(pb, index[i].packet_number); |
||
847 | put_le16(pb, index[i].packet_count); |
||
848 | } |
||
849 | |||
850 | 542993b0 | Konstantin Andreyev | return 0; |
851 | } |
||
852 | |||
853 | static int asf_write_trailer(AVFormatContext *s) |
||
854 | { |
||
855 | ASFContext *asf = s->priv_data; |
||
856 | 982e53fe | Calcium | int64_t file_size,data_size; |
857 | 542993b0 | Konstantin Andreyev | |
858 | /* flush the current packet */
|
||
859 | if (asf->pb.buf_ptr > asf->pb.buffer)
|
||
860 | flush_packet(s); |
||
861 | |||
862 | 982e53fe | Calcium | /* write index */
|
863 | 899681cd | Björn Axelsson | data_size = url_ftell(s->pb); |
864 | 982e53fe | Calcium | 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 | 899681cd | Björn Axelsson | put_flush_packet(s->pb); |
868 | 982e53fe | Calcium | |
869 | 899681cd | Björn Axelsson | if (asf->is_streamed || url_is_streamed(s->pb)) {
|
870 | 542993b0 | Konstantin Andreyev | put_chunk(s, 0x4524, 0, 0); /* end of stream */ |
871 | } else {
|
||
872 | /* rewrite an updated header */
|
||
873 | 899681cd | Björn Axelsson | file_size = url_ftell(s->pb); |
874 | url_fseek(s->pb, 0, SEEK_SET);
|
||
875 | 982e53fe | Calcium | asf_write_header1(s, file_size, data_size - asf->data_offset); |
876 | 542993b0 | Konstantin Andreyev | } |
877 | |||
878 | 899681cd | Björn Axelsson | put_flush_packet(s->pb); |
879 | 982e53fe | Calcium | av_free(asf->index_ptr); |
880 | 542993b0 | Konstantin Andreyev | return 0; |
881 | } |
||
882 | |||
883 | b250f9c6 | Aurelien Jacobs | #if CONFIG_ASF_MUXER
|
884 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_asf_muxer = { |
885 | 542993b0 | Konstantin Andreyev | "asf",
|
886 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("ASF format"),
|
887 | 542993b0 | Konstantin Andreyev | "video/x-ms-asf",
|
888 | 87094371 | Michael Niedermayer | "asf,wmv,wma",
|
889 | 542993b0 | Konstantin Andreyev | sizeof(ASFContext),
|
890 | b250f9c6 | Aurelien Jacobs | #if CONFIG_LIBMP3LAME
|
891 | 542993b0 | Konstantin Andreyev | 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 | 982e53fe | Calcium | .flags = AVFMT_GLOBALHEADER, |
900 | 1a40491e | Daniel Verkamp | .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
901 | 542993b0 | Konstantin Andreyev | }; |
902 | ff70e601 | Måns Rullgård | #endif
|
903 | 542993b0 | Konstantin Andreyev | |
904 | b250f9c6 | Aurelien Jacobs | #if CONFIG_ASF_STREAM_MUXER
|
905 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_asf_stream_muxer = { |
906 | 542993b0 | Konstantin Andreyev | "asf_stream",
|
907 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("ASF format"),
|
908 | 542993b0 | Konstantin Andreyev | "video/x-ms-asf",
|
909 | 87094371 | Michael Niedermayer | "asf,wmv,wma",
|
910 | 542993b0 | Konstantin Andreyev | sizeof(ASFContext),
|
911 | b250f9c6 | Aurelien Jacobs | #if CONFIG_LIBMP3LAME
|
912 | 542993b0 | Konstantin Andreyev | 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 | 982e53fe | Calcium | .flags = AVFMT_GLOBALHEADER, |
921 | 1a40491e | Daniel Verkamp | .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_tags, ff_codec_wav_tags, 0}, |
922 | 542993b0 | Konstantin Andreyev | }; |
923 | ff70e601 | Måns Rullgård | #endif //CONFIG_ASF_STREAM_MUXER |