OLD | NEW |
1 /* | 1 /* |
2 * ASF muxer | 2 * ASF muxer |
3 * Copyright (c) 2000, 2001 Fabrice Bellard | 3 * Copyright (c) 2000, 2001 Fabrice Bellard |
4 * | 4 * |
5 * This file is part of FFmpeg. | 5 * This file is part of FFmpeg. |
6 * | 6 * |
7 * FFmpeg is free software; you can redistribute it and/or | 7 * FFmpeg is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Lesser General Public | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2.1 of the License, or (at your option) any later version. | 10 * version 2.1 of the License, or (at your option) any later version. |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 }; | 196 }; |
197 | 197 |
198 #define PREROLL_TIME 3100 | 198 #define PREROLL_TIME 3100 |
199 | 199 |
200 static void put_guid(ByteIOContext *s, const ff_asf_guid *g) | 200 static void put_guid(ByteIOContext *s, const ff_asf_guid *g) |
201 { | 201 { |
202 assert(sizeof(*g) == 16); | 202 assert(sizeof(*g) == 16); |
203 put_buffer(s, *g, sizeof(*g)); | 203 put_buffer(s, *g, sizeof(*g)); |
204 } | 204 } |
205 | 205 |
206 static void put_str16_nolen(ByteIOContext *s, const char *tag); | 206 static int put_str16_nolen(ByteIOContext *s, const char *tag) |
| 207 { |
| 208 const uint8_t *q = tag; |
| 209 int ret = 0; |
| 210 |
| 211 while (*q) { |
| 212 uint32_t ch; |
| 213 uint16_t tmp; |
| 214 |
| 215 GET_UTF8(ch, *q++, break;) |
| 216 PUT_UTF16(ch, tmp, put_le16(s, tmp);ret += 2;) |
| 217 } |
| 218 put_le16(s, 0); |
| 219 ret += 2; |
| 220 return ret; |
| 221 } |
| 222 |
207 static void put_str16(ByteIOContext *s, const char *tag) | 223 static void put_str16(ByteIOContext *s, const char *tag) |
208 { | 224 { |
209 put_le16(s,strlen(tag) + 1); | 225 int len; |
210 put_str16_nolen(s, tag); | 226 uint8_t *pb; |
211 } | 227 ByteIOContext *dyn_buf; |
| 228 if (url_open_dyn_buf(&dyn_buf) < 0) |
| 229 return; |
212 | 230 |
213 static void put_str16_nolen(ByteIOContext *s, const char *tag) | 231 put_str16_nolen(dyn_buf, tag); |
214 { | 232 len = url_close_dyn_buf(dyn_buf, &pb); |
215 int c; | 233 put_le16(s, len); |
216 | 234 put_buffer(s, pb, len); |
217 do{ | 235 av_freep(&pb); |
218 c = (uint8_t)*tag++; | |
219 put_le16(s, c); | |
220 }while(c); | |
221 } | 236 } |
222 | 237 |
223 static int64_t put_header(ByteIOContext *pb, const ff_asf_guid *g) | 238 static int64_t put_header(ByteIOContext *pb, const ff_asf_guid *g) |
224 { | 239 { |
225 int64_t pos; | 240 int64_t pos; |
226 | 241 |
227 pos = url_ftell(pb); | 242 pos = url_ftell(pb); |
228 put_guid(pb, g); | 243 put_guid(pb, g); |
229 put_le64(pb, 24); | 244 put_le64(pb, 24); |
230 return pos; | 245 return pos; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 t = ti * INT64_C(10000000); | 280 t = ti * INT64_C(10000000); |
266 t += INT64_C(116444736000000000); | 281 t += INT64_C(116444736000000000); |
267 return t; | 282 return t; |
268 } | 283 } |
269 | 284 |
270 /* write the header (used two times if non streamed) */ | 285 /* write the header (used two times if non streamed) */ |
271 static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
_chunk_size) | 286 static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data
_chunk_size) |
272 { | 287 { |
273 ASFContext *asf = s->priv_data; | 288 ASFContext *asf = s->priv_data; |
274 ByteIOContext *pb = s->pb; | 289 ByteIOContext *pb = s->pb; |
275 AVMetadataTag *title, *author, *copyright, *comment; | 290 AVMetadataTag *tags[5]; |
276 int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; | 291 int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; |
277 int has_title; | 292 int has_title; |
278 int metadata_count; | 293 int metadata_count; |
279 AVCodecContext *enc; | 294 AVCodecContext *enc; |
280 int64_t header_offset, cur_pos, hpos; | 295 int64_t header_offset, cur_pos, hpos; |
281 int bit_rate; | 296 int bit_rate; |
282 int64_t duration; | 297 int64_t duration; |
283 | 298 |
284 title = av_metadata_get(s->metadata, "title" , NULL, 0); | 299 tags[0] = av_metadata_get(s->metadata, "title" , NULL, 0); |
285 author = av_metadata_get(s->metadata, "author" , NULL, 0); | 300 tags[1] = av_metadata_get(s->metadata, "author" , NULL, 0); |
286 copyright = av_metadata_get(s->metadata, "copyright", NULL, 0); | 301 tags[2] = av_metadata_get(s->metadata, "copyright", NULL, 0); |
287 comment = av_metadata_get(s->metadata, "comment" , NULL, 0); | 302 tags[3] = av_metadata_get(s->metadata, "comment" , NULL, 0); |
| 303 tags[4] = av_metadata_get(s->metadata, "rating" , NULL, 0); |
288 | 304 |
289 duration = asf->duration + PREROLL_TIME * 10000; | 305 duration = asf->duration + PREROLL_TIME * 10000; |
290 has_title = title || author || copyright || comment; | 306 has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; |
291 metadata_count = s->metadata ? s->metadata->count : 0; | 307 metadata_count = s->metadata ? s->metadata->count : 0; |
292 | 308 |
293 bit_rate = 0; | 309 bit_rate = 0; |
294 for(n=0;n<s->nb_streams;n++) { | 310 for(n=0;n<s->nb_streams;n++) { |
295 enc = s->streams[n]->codec; | 311 enc = s->streams[n]->codec; |
296 | 312 |
297 av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ | 313 av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ |
298 | 314 |
299 bit_rate += enc->bit_rate; | 315 bit_rate += enc->bit_rate; |
300 } | 316 } |
(...skipping 27 matching lines...) Expand all Loading... |
328 | 344 |
329 /* unknown headers */ | 345 /* unknown headers */ |
330 hpos = put_header(pb, &ff_asf_head1_guid); | 346 hpos = put_header(pb, &ff_asf_head1_guid); |
331 put_guid(pb, &ff_asf_head2_guid); | 347 put_guid(pb, &ff_asf_head2_guid); |
332 put_le32(pb, 6); | 348 put_le32(pb, 6); |
333 put_le16(pb, 0); | 349 put_le16(pb, 0); |
334 end_header(pb, hpos); | 350 end_header(pb, hpos); |
335 | 351 |
336 /* title and other infos */ | 352 /* title and other infos */ |
337 if (has_title) { | 353 if (has_title) { |
| 354 int len; |
| 355 uint8_t *buf; |
| 356 ByteIOContext *dyn_buf; |
| 357 |
| 358 if (url_open_dyn_buf(&dyn_buf) < 0) |
| 359 return AVERROR(ENOMEM); |
| 360 |
338 hpos = put_header(pb, &ff_asf_comment_header); | 361 hpos = put_header(pb, &ff_asf_comment_header); |
339 put_le16(pb, title ? 2 * (strlen(title->value ) + 1) : 0); | 362 |
340 put_le16(pb, author ? 2 * (strlen(author->value ) + 1) : 0); | 363 for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { |
341 put_le16(pb, copyright ? 2 * (strlen(copyright->value) + 1) : 0); | 364 len = tags[n] ? put_str16_nolen(dyn_buf, tags[n]->value) : 0; |
342 put_le16(pb, comment ? 2 * (strlen(comment->value ) + 1) : 0); | 365 put_le16(pb, len); |
343 put_le16(pb, 0); | 366 } |
344 if (title ) put_str16_nolen(pb, title->value ); | 367 len = url_close_dyn_buf(dyn_buf, &buf); |
345 if (author ) put_str16_nolen(pb, author->value ); | 368 put_buffer(pb, buf, len); |
346 if (copyright) put_str16_nolen(pb, copyright->value); | 369 av_freep(&buf); |
347 if (comment ) put_str16_nolen(pb, comment->value ); | |
348 end_header(pb, hpos); | 370 end_header(pb, hpos); |
349 } | 371 } |
350 if (metadata_count) { | 372 if (metadata_count) { |
351 AVMetadataTag *tag = NULL; | 373 AVMetadataTag *tag = NULL; |
352 hpos = put_header(pb, &ff_asf_extended_content_header); | 374 hpos = put_header(pb, &ff_asf_extended_content_header); |
353 put_le16(pb, metadata_count); | 375 put_le16(pb, metadata_count); |
354 while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_S
UFFIX))) { | 376 while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_S
UFFIX))) { |
355 put_le16(pb, 2*(strlen(tag->key) + 3) + 1); | 377 put_str16(pb, tag->key); |
356 put_le16(pb, 'W'); | |
357 put_le16(pb, 'M'); | |
358 put_le16(pb, '/'); | |
359 put_str16_nolen(pb, tag->key); | |
360 put_le16(pb, 0); | 378 put_le16(pb, 0); |
361 put_le16(pb, 2*strlen(tag->value) + 1); | 379 put_str16(pb, tag->value); |
362 put_str16_nolen(pb, tag->value); | |
363 } | 380 } |
364 end_header(pb, hpos); | 381 end_header(pb, hpos); |
365 } | 382 } |
366 | 383 |
367 /* stream headers */ | 384 /* stream headers */ |
368 for(n=0;n<s->nb_streams;n++) { | 385 for(n=0;n<s->nb_streams;n++) { |
369 int64_t es_pos; | 386 int64_t es_pos; |
370 // ASFStream *stream = &asf->streams[n]; | 387 // ASFStream *stream = &asf->streams[n]; |
371 | 388 |
372 enc = s->streams[n]->codec; | 389 enc = s->streams[n]->codec; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 end_header(pb, hpos); | 459 end_header(pb, hpos); |
443 } | 460 } |
444 | 461 |
445 /* media comments */ | 462 /* media comments */ |
446 | 463 |
447 hpos = put_header(pb, &ff_asf_codec_comment_header); | 464 hpos = put_header(pb, &ff_asf_codec_comment_header); |
448 put_guid(pb, &ff_asf_codec_comment1_header); | 465 put_guid(pb, &ff_asf_codec_comment1_header); |
449 put_le32(pb, s->nb_streams); | 466 put_le32(pb, s->nb_streams); |
450 for(n=0;n<s->nb_streams;n++) { | 467 for(n=0;n<s->nb_streams;n++) { |
451 AVCodec *p; | 468 AVCodec *p; |
| 469 const char *desc; |
| 470 int len; |
| 471 uint8_t *buf; |
| 472 ByteIOContext *dyn_buf; |
452 | 473 |
453 enc = s->streams[n]->codec; | 474 enc = s->streams[n]->codec; |
454 p = avcodec_find_encoder(enc->codec_id); | 475 p = avcodec_find_encoder(enc->codec_id); |
455 | 476 |
456 if(enc->codec_type == CODEC_TYPE_AUDIO) | 477 if(enc->codec_type == CODEC_TYPE_AUDIO) |
457 put_le16(pb, 2); | 478 put_le16(pb, 2); |
458 else if(enc->codec_type == CODEC_TYPE_VIDEO) | 479 else if(enc->codec_type == CODEC_TYPE_VIDEO) |
459 put_le16(pb, 1); | 480 put_le16(pb, 1); |
460 else | 481 else |
461 put_le16(pb, -1); | 482 put_le16(pb, -1); |
462 | 483 |
463 if(enc->codec_id == CODEC_ID_WMAV2) | 484 if(enc->codec_id == CODEC_ID_WMAV2) |
464 put_str16(pb, "Windows Media Audio V8"); | 485 desc = "Windows Media Audio V8"; |
465 else | 486 else |
466 put_str16(pb, p ? p->name : enc->codec_name); | 487 desc = p ? p->name : enc->codec_name; |
| 488 |
| 489 if ( url_open_dyn_buf(&dyn_buf) < 0) |
| 490 return AVERROR(ENOMEM); |
| 491 |
| 492 put_str16_nolen(dyn_buf, desc); |
| 493 len = url_close_dyn_buf(dyn_buf, &buf); |
| 494 put_le16(pb, len / 2); // "number of characters" = length in bytes / 2 |
| 495 |
| 496 put_buffer(pb, buf, len); |
| 497 av_freep(&buf); |
| 498 |
467 put_le16(pb, 0); /* no parameters */ | 499 put_le16(pb, 0); /* no parameters */ |
468 | 500 |
469 | 501 |
470 /* id */ | 502 /* id */ |
471 if (enc->codec_type == CODEC_TYPE_AUDIO) { | 503 if (enc->codec_type == CODEC_TYPE_AUDIO) { |
472 put_le16(pb, 2); | 504 put_le16(pb, 2); |
473 put_le16(pb, enc->codec_tag); | 505 put_le16(pb, enc->codec_tag); |
474 } else { | 506 } else { |
475 put_le16(pb, 4); | 507 put_le16(pb, 4); |
476 put_le32(pb, enc->codec_tag); | 508 put_le32(pb, enc->codec_tag); |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 #endif | 905 #endif |
874 CODEC_ID_MSMPEG4V3, | 906 CODEC_ID_MSMPEG4V3, |
875 asf_write_stream_header, | 907 asf_write_stream_header, |
876 asf_write_packet, | 908 asf_write_packet, |
877 asf_write_trailer, | 909 asf_write_trailer, |
878 .flags = AVFMT_GLOBALHEADER, | 910 .flags = AVFMT_GLOBALHEADER, |
879 .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_ta
gs, ff_codec_wav_tags, 0}, | 911 .codec_tag= (const AVCodecTag* const []){codec_asf_bmp_tags, ff_codec_bmp_ta
gs, ff_codec_wav_tags, 0}, |
880 .metadata_conv = ff_asf_metadata_conv, | 912 .metadata_conv = ff_asf_metadata_conv, |
881 }; | 913 }; |
882 #endif //CONFIG_ASF_STREAM_MUXER | 914 #endif //CONFIG_ASF_STREAM_MUXER |
OLD | NEW |