static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, uint32_t count) { ByteIOContext *pb = &s->pb; int i; put_guid(pb, &simple_index_header); put_le64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count); put_guid(pb, &my_guid); put_le64(pb, ASF_INDEXED_INTERVAL); put_le32(pb, max); put_le32(pb, count); for(i=0; i<count; i++) { put_le32(pb, index[i].packet_number); put_le16(pb, index[i].packet_count); } return 0; }
static int64_t put_header(ByteIOContext *pb, const GUID *g) { int64_t pos; pos = url_ftell(pb); put_guid(pb, g); put_le64(pb, 24); return pos; }
static int asf_write_markers(AVFormatContext *s) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; int i; AVRational scale = {1, 10000000}; int64_t hpos = put_header(pb, &ff_asf_marker_header); put_guid(pb, &ff_asf_reserved_4); // ASF spec mandates this reserved value avio_wl32(pb, s->nb_chapters); // markers count avio_wl16(pb, 0); // ASF spec mandates 0 for this avio_wl16(pb, 0); // name length 0, no name given for (i = 0; i < s->nb_chapters; i++) { AVChapter *c = s->chapters[i]; AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0); int64_t pres_time = av_rescale_q(c->start, c->time_base, scale); uint64_t offset; int32_t send_time = get_send_time(asf, pres_time, &offset); int len = 0; uint8_t *buf; AVIOContext *dyn_buf; if (t) { if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); avio_put_str16le(dyn_buf, t->value); len = avio_close_dyn_buf(dyn_buf, &buf); } avio_wl64(pb, offset); // offset of the packet with send_time avio_wl64(pb, pres_time + PREROLL_TIME * 10000); // presentation time avio_wl16(pb, 12 + len); // entry length avio_wl32(pb, send_time); // send time avio_wl32(pb, 0); // flags, should be 0 avio_wl32(pb, len / 2); // marker desc length in WCHARS! if (t) { avio_write(pb, buf, len); // marker desc av_freep(&buf); } } end_header(pb, hpos); return 0; }
/* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; ByteIOContext *pb = s->pb; AVMetadataTag *title, *author, *copyright, *comment; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; int metadata_count; AVCodecContext *enc; int64_t header_offset, cur_pos, hpos; int bit_rate; int64_t duration; title = av_metadata_get(s->metadata, "title" , NULL, 0); author = av_metadata_get(s->metadata, "author" , NULL, 0); copyright = av_metadata_get(s->metadata, "copyright", NULL, 0); comment = av_metadata_get(s->metadata, "comment" , NULL, 0); duration = asf->duration + PREROLL_TIME * 10000; has_title = title || author || copyright || comment; metadata_count = s->metadata ? s->metadata->count : 0; bit_rate = 0; for(n=0;n<s->nb_streams;n++) { enc = s->streams[n]->codec; av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } put_guid(pb, &ff_asf_header); put_le64(pb, -1); /* header length, will be patched after */ put_le32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ put_byte(pb, 1); /* ??? */ put_byte(pb, 2); /* ??? */ /* file header */ header_offset = url_ftell(pb); hpos = put_header(pb, &ff_asf_file_header); put_guid(pb, &ff_asf_my_guid); put_le64(pb, file_size); file_time = 0; put_le64(pb, unix_to_file_time(file_time)); put_le64(pb, asf->nb_packets); /* number of packets */ put_le64(pb, duration); /* end time stamp (in 100ns units) */ put_le64(pb, asf->duration); /* duration (in 100ns units) */ put_le64(pb, PREROLL_TIME); /* start time stamp */ put_le32(pb, (asf->is_streamed || url_is_streamed(pb)) ? 3 : 2); /* ??? */ put_le32(pb, asf->packet_size); /* packet size */ put_le32(pb, asf->packet_size); /* packet size */ put_le32(pb, bit_rate); /* Nominal data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); put_guid(pb, &ff_asf_head2_guid); put_le32(pb, 6); put_le16(pb, 0); end_header(pb, hpos); /* title and other infos */ if (has_title) { hpos = put_header(pb, &ff_asf_comment_header); put_le16(pb, title ? 2 * (strlen(title->value ) + 1) : 0); put_le16(pb, author ? 2 * (strlen(author->value ) + 1) : 0); put_le16(pb, copyright ? 2 * (strlen(copyright->value) + 1) : 0); put_le16(pb, comment ? 2 * (strlen(comment->value ) + 1) : 0); put_le16(pb, 0); if (title ) put_str16_nolen(pb, title->value ); if (author ) put_str16_nolen(pb, author->value ); if (copyright) put_str16_nolen(pb, copyright->value); if (comment ) put_str16_nolen(pb, comment->value ); end_header(pb, hpos); } if (metadata_count) { AVMetadataTag *tag = NULL; hpos = put_header(pb, &ff_asf_extended_content_header); put_le16(pb, metadata_count); while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { put_le16(pb, 2*(strlen(tag->key) + 3) + 1); put_le16(pb, 'W'); put_le16(pb, 'M'); put_le16(pb, '/'); put_str16_nolen(pb, tag->key); put_le16(pb, 0); put_le16(pb, 2*strlen(tag->value) + 1); put_str16_nolen(pb, tag->value); } end_header(pb, hpos); } /* stream headers */ for(n=0;n<s->nb_streams;n++) { int64_t es_pos; // ASFStream *stream = &asf->streams[n]; enc = s->streams[n]->codec; asf->streams[n].num = n + 1; asf->streams[n].seq = 0; switch(enc->codec_type) { case CODEC_TYPE_AUDIO: wav_extra_size = 0; extra_size = 18 + wav_extra_size; extra_size2 = 8; break; default: case CODEC_TYPE_VIDEO: wav_extra_size = enc->extradata_size; extra_size = 0x33 + wav_extra_size; extra_size2 = 0; break; } hpos = put_header(pb, &ff_asf_stream_header); if (enc->codec_type == CODEC_TYPE_AUDIO) { put_guid(pb, &ff_asf_audio_stream); put_guid(pb, &ff_asf_audio_conceal_spread); } else { put_guid(pb, &ff_asf_video_stream); put_guid(pb, &ff_asf_video_conceal_none); } put_le64(pb, 0); /* ??? */ es_pos = url_ftell(pb); put_le32(pb, extra_size); /* wav header len */ put_le32(pb, extra_size2); /* additional data len */ put_le16(pb, n + 1); /* stream number */ put_le32(pb, 0); /* ??? */ if (enc->codec_type == CODEC_TYPE_AUDIO) { /* WAVEFORMATEX header */ int wavsize = put_wav_header(pb, enc); 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)) { wavsize += 2; put_le16(pb, 0); } if (wavsize < 0) return -1; if (wavsize != extra_size) { cur_pos = url_ftell(pb); url_fseek(pb, es_pos, SEEK_SET); put_le32(pb, wavsize); /* wav header len */ url_fseek(pb, cur_pos, SEEK_SET); } /* ERROR Correction */ put_byte(pb, 0x01); if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align){ put_le16(pb, 0x0190); put_le16(pb, 0x0190); }else{ put_le16(pb, enc->block_align); put_le16(pb, enc->block_align); } put_le16(pb, 0x01); put_byte(pb, 0x00); } else { put_le32(pb, enc->width); put_le32(pb, enc->height); put_byte(pb, 2); /* ??? */ put_le16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ put_bmp_header(pb, enc, codec_bmp_tags, 1); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); put_guid(pb, &ff_asf_codec_comment1_header); put_le32(pb, s->nb_streams); for(n=0;n<s->nb_streams;n++) { AVCodec *p; enc = s->streams[n]->codec; p = avcodec_find_encoder(enc->codec_id); if(enc->codec_type == CODEC_TYPE_AUDIO) put_le16(pb, 2); else if(enc->codec_type == CODEC_TYPE_VIDEO) put_le16(pb, 1); else put_le16(pb, -1); if(enc->codec_id == CODEC_ID_WMAV2) put_str16(pb, "Windows Media Audio V8"); else put_str16(pb, p ? p->name : enc->codec_name); put_le16(pb, 0); /* no parameters */ /* id */ if (enc->codec_type == CODEC_TYPE_AUDIO) { put_le16(pb, 2); put_le16(pb, enc->codec_tag); } else { put_le16(pb, 4); put_le32(pb, enc->codec_tag); } if(!enc->codec_tag) return -1; } end_header(pb, hpos); /* patch the header size fields */ cur_pos = url_ftell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { header_size += 8 + 30 + 50; url_fseek(pb, header_offset - 10 - 30, SEEK_SET); put_le16(pb, header_size); url_fseek(pb, header_offset - 2 - 30, SEEK_SET); put_le16(pb, header_size); header_size -= 8 + 30 + 50; } header_size += 24 + 6; url_fseek(pb, header_offset - 14, SEEK_SET); put_le64(pb, header_size); url_fseek(pb, cur_pos, SEEK_SET); /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; put_guid(pb, &ff_asf_data_header); put_le64(pb, data_chunk_size); put_guid(pb, &ff_asf_my_guid); put_le64(pb, asf->nb_packets); /* nb packets */ put_byte(pb, 1); /* ??? */ put_byte(pb, 1); /* ??? */ return 0; }
/* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; AVMetadataTag *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; int metadata_count; AVCodecContext *enc; int64_t header_offset, cur_pos, hpos; int bit_rate; int64_t duration; ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL); tags[0] = av_metadata_get(s->metadata, "title" , NULL, 0); tags[1] = av_metadata_get(s->metadata, "author" , NULL, 0); tags[2] = av_metadata_get(s->metadata, "copyright", NULL, 0); tags[3] = av_metadata_get(s->metadata, "comment" , NULL, 0); tags[4] = av_metadata_get(s->metadata, "rating" , NULL, 0); duration = asf->duration + PREROLL_TIME * 10000; has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; metadata_count = s->metadata ? s->metadata->count : 0; bit_rate = 0; for(n = 0; n < s->nb_streams; n++) { enc = s->streams[n]->codec; av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } put_guid(pb, &ff_asf_header); avio_wl64(pb, -1); /* header length, will be patched after */ avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 2); /* ??? */ /* file header */ header_offset = avio_tell(pb); hpos = put_header(pb, &ff_asf_file_header); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, file_size); file_time = 0; avio_wl64(pb, unix_to_file_time(file_time)); avio_wl64(pb, asf->nb_packets); /* number of packets */ avio_wl64(pb, duration); /* end time stamp (in 100ns units) */ avio_wl64(pb, asf->duration); /* duration (in 100ns units) */ avio_wl64(pb, PREROLL_TIME); /* start time stamp */ avio_wl32(pb, (asf->is_streamed || !pb->seekable ) ? 3 : 2); /* ??? */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, bit_rate); /* Nominal data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); put_guid(pb, &ff_asf_head2_guid); avio_wl32(pb, 6); avio_wl16(pb, 0); end_header(pb, hpos); /* title and other infos */ if (has_title) { int len; uint8_t *buf; AVIOContext *dyn_buf; if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); hpos = put_header(pb, &ff_asf_comment_header); for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0; avio_wl16(pb, len); } len = avio_close_dyn_buf(dyn_buf, &buf); avio_write(pb, buf, len); av_freep(&buf); end_header(pb, hpos); } if (metadata_count) { AVMetadataTag *tag = NULL; hpos = put_header(pb, &ff_asf_extended_content_header); avio_wl16(pb, metadata_count); while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { put_str16(pb, tag->key); avio_wl16(pb, 0); put_str16(pb, tag->value); } end_header(pb, hpos); } /* stream headers */ for(n = 0; n < s->nb_streams; n++) { int64_t es_pos; // ASFStream *stream = &asf->streams[n]; enc = s->streams[n]->codec; asf->streams[n].num = n + 1; asf->streams[n].seq = 0; switch(enc->codec_type) { case AVMEDIA_TYPE_AUDIO: wav_extra_size = 0; extra_size = 18 + wav_extra_size; extra_size2 = 8; break; default: case AVMEDIA_TYPE_VIDEO: wav_extra_size = enc->extradata_size; extra_size = 0x33 + wav_extra_size; extra_size2 = 0; break; } hpos = put_header(pb, &ff_asf_stream_header); if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { put_guid(pb, &ff_asf_audio_stream); put_guid(pb, &ff_asf_audio_conceal_spread); } else { put_guid(pb, &ff_asf_video_stream); put_guid(pb, &ff_asf_video_conceal_none); } avio_wl64(pb, 0); /* ??? */ es_pos = avio_tell(pb); avio_wl32(pb, extra_size); /* wav header len */ avio_wl32(pb, extra_size2); /* additional data len */ avio_wl16(pb, n + 1); /* stream number */ avio_wl32(pb, 0); /* ??? */ if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { /* WAVEFORMATEX header */ int wavsize = ff_put_wav_header(pb, enc); 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)) { wavsize += 2; avio_wl16(pb, 0); } if (wavsize < 0) return -1; if (wavsize != extra_size) { cur_pos = avio_tell(pb); avio_seek(pb, es_pos, SEEK_SET); avio_wl32(pb, wavsize); /* wav header len */ avio_seek(pb, cur_pos, SEEK_SET); } /* ERROR Correction */ avio_w8(pb, 0x01); if(enc->codec_id == CODEC_ID_ADPCM_G726 || !enc->block_align) { avio_wl16(pb, 0x0190); avio_wl16(pb, 0x0190); } else { avio_wl16(pb, enc->block_align); avio_wl16(pb, enc->block_align); } avio_wl16(pb, 0x01); avio_w8(pb, 0x00); } else { avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_w8(pb, 2); /* ??? */ avio_wl16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); put_guid(pb, &ff_asf_codec_comment1_header); avio_wl32(pb, s->nb_streams); for(n = 0; n < s->nb_streams; n++) { AVCodec *p; const char *desc; int len; uint8_t *buf; AVIOContext *dyn_buf; enc = s->streams[n]->codec; p = avcodec_find_encoder(enc->codec_id); if(enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl16(pb, 2); else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl16(pb, 1); else avio_wl16(pb, -1); if(enc->codec_id == CODEC_ID_WMAV2) desc = "Windows Media Audio V8"; else desc = p ? p->name : enc->codec_name; if ( avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); avio_put_str16le(dyn_buf, desc); len = avio_close_dyn_buf(dyn_buf, &buf); avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 avio_write(pb, buf, len); av_freep(&buf); avio_wl16(pb, 0); /* no parameters */ /* id */ if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { avio_wl16(pb, 2); avio_wl16(pb, enc->codec_tag); } else { avio_wl16(pb, 4); avio_wl32(pb, enc->codec_tag); } if(!enc->codec_tag) return -1; } end_header(pb, hpos); /* patch the header size fields */ cur_pos = avio_tell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { header_size += 8 + 30 + 50; avio_seek(pb, header_offset - 10 - 30, SEEK_SET); avio_wl16(pb, header_size); avio_seek(pb, header_offset - 2 - 30, SEEK_SET); avio_wl16(pb, header_size); header_size -= 8 + 30 + 50; } header_size += 24 + 6; avio_seek(pb, header_offset - 14, SEEK_SET); avio_wl64(pb, header_size); avio_seek(pb, cur_pos, SEEK_SET); /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, asf->nb_packets); /* nb packets */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 1); /* ??? */ return 0; }
/* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; AVIOContext *pb = s->pb; AVDictionaryEntry *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; int metadata_count; AVCodecParameters *par; int64_t header_offset, cur_pos, hpos; int bit_rate; uint64_t play_duration, send_duration; ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL); tags[0] = av_dict_get(s->metadata, "title", NULL, 0); tags[1] = av_dict_get(s->metadata, "author", NULL, 0); tags[2] = av_dict_get(s->metadata, "copyright", NULL, 0); tags[3] = av_dict_get(s->metadata, "comment", NULL, 0); tags[4] = av_dict_get(s->metadata, "rating", NULL, 0); if (asf->duration > UINT64_MAX / 10000 - PREROLL_TIME) { av_log(s, AV_LOG_WARNING, "Duration %"PRIu64" too large\n", asf->duration); if (s->error_recognition & AV_EF_EXPLODE) return AVERROR(ERANGE); send_duration = 0; play_duration = 0; } else { send_duration = asf->duration * 10000; play_duration = (asf->duration + PREROLL_TIME) * 10000; } has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; metadata_count = av_dict_count(s->metadata); bit_rate = 0; for (n = 0; n < s->nb_streams; n++) { par = s->streams[n]->codecpar; avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += par->bit_rate; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } put_guid(pb, &ff_asf_header); avio_wl64(pb, -1); /* header length, will be patched after */ avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 2); /* ??? */ /* file header */ header_offset = avio_tell(pb); hpos = put_header(pb, &ff_asf_file_header); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, file_size); file_time = 0; avio_wl64(pb, unix_to_file_time(file_time)); avio_wl64(pb, asf->nb_packets); /* number of packets */ avio_wl64(pb, play_duration); /* end time stamp (in 100ns units) */ avio_wl64(pb, send_duration); /* duration (in 100ns units) */ avio_wl64(pb, PREROLL_TIME); /* start time stamp */ avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2); /* ??? */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, s->packet_size); /* packet size */ avio_wl32(pb, bit_rate); /* Nominal data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); put_guid(pb, &ff_asf_head2_guid); avio_wl32(pb, 6); avio_wl16(pb, 0); end_header(pb, hpos); /* title and other info */ if (has_title) { int len; uint8_t *buf; AVIOContext *dyn_buf; if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); hpos = put_header(pb, &ff_asf_comment_header); for (n = 0; n < FF_ARRAY_ELEMS(tags); n++) { len = tags[n] ? avio_put_str16le(dyn_buf, tags[n]->value) : 0; avio_wl16(pb, len); } len = avio_close_dyn_buf(dyn_buf, &buf); avio_write(pb, buf, len); av_freep(&buf); end_header(pb, hpos); } if (metadata_count) { AVDictionaryEntry *tag = NULL; hpos = put_header(pb, &ff_asf_extended_content_header); avio_wl16(pb, metadata_count); while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { put_str16(pb, tag->key); avio_wl16(pb, 0); put_str16(pb, tag->value); } end_header(pb, hpos); } /* chapters using ASF markers */ if (!asf->is_streamed && s->nb_chapters) { int ret; if (ret = asf_write_markers(s)) return ret; } /* stream headers */ for (n = 0; n < s->nb_streams; n++) { int64_t es_pos; // ASFStream *stream = &asf->streams[n]; par = s->streams[n]->codecpar; asf->streams[n].num = n + 1; asf->streams[n].seq = 0; switch (par->codec_type) { case AVMEDIA_TYPE_AUDIO: wav_extra_size = 0; extra_size = 18 + wav_extra_size; extra_size2 = 8; break; default: case AVMEDIA_TYPE_VIDEO: wav_extra_size = par->extradata_size; extra_size = 0x33 + wav_extra_size; extra_size2 = 0; break; } hpos = put_header(pb, &ff_asf_stream_header); if (par->codec_type == AVMEDIA_TYPE_AUDIO) { put_guid(pb, &ff_asf_audio_stream); put_guid(pb, &ff_asf_audio_conceal_spread); } else { put_guid(pb, &ff_asf_video_stream); put_guid(pb, &ff_asf_video_conceal_none); } avio_wl64(pb, 0); /* ??? */ es_pos = avio_tell(pb); avio_wl32(pb, extra_size); /* wav header len */ avio_wl32(pb, extra_size2); /* additional data len */ avio_wl16(pb, n + 1); /* stream number */ avio_wl32(pb, 0); /* ??? */ if (par->codec_type == AVMEDIA_TYPE_AUDIO) { /* WAVEFORMATEX header */ int wavsize = ff_put_wav_header(s, pb, par); if (wavsize < 0) return -1; if (wavsize != extra_size) { cur_pos = avio_tell(pb); avio_seek(pb, es_pos, SEEK_SET); avio_wl32(pb, wavsize); /* wav header len */ avio_seek(pb, cur_pos, SEEK_SET); } /* ERROR Correction */ avio_w8(pb, 0x01); if (par->codec_id == AV_CODEC_ID_ADPCM_G726 || !par->block_align) { avio_wl16(pb, 0x0190); avio_wl16(pb, 0x0190); } else { avio_wl16(pb, par->block_align); avio_wl16(pb, par->block_align); } avio_wl16(pb, 0x01); avio_w8(pb, 0x00); } else { avio_wl32(pb, par->width); avio_wl32(pb, par->height); avio_w8(pb, 2); /* ??? */ avio_wl16(pb, 40 + par->extradata_size); /* size */ /* BITMAPINFOHEADER header */ ff_put_bmp_header(pb, par, ff_codec_bmp_tags, 1); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); put_guid(pb, &ff_asf_codec_comment1_header); avio_wl32(pb, s->nb_streams); for (n = 0; n < s->nb_streams; n++) { const AVCodecDescriptor *codec_desc; const char *desc; par = s->streams[n]->codecpar; codec_desc = avcodec_descriptor_get(par->codec_id); if (par->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl16(pb, 2); else if (par->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl16(pb, 1); else avio_wl16(pb, -1); if (par->codec_id == AV_CODEC_ID_WMAV2) desc = "Windows Media Audio V8"; else desc = codec_desc ? codec_desc->name : NULL; if (desc) { AVIOContext *dyn_buf; uint8_t *buf; int len; if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); avio_put_str16le(dyn_buf, desc); len = avio_close_dyn_buf(dyn_buf, &buf); avio_wl16(pb, len / 2); // "number of characters" = length in bytes / 2 avio_write(pb, buf, len); av_freep(&buf); } else avio_wl16(pb, 0); avio_wl16(pb, 0); /* no parameters */ /* id */ if (par->codec_type == AVMEDIA_TYPE_AUDIO) { avio_wl16(pb, 2); avio_wl16(pb, par->codec_tag); } else { avio_wl16(pb, 4); avio_wl32(pb, par->codec_tag); } if (!par->codec_tag) return -1; } end_header(pb, hpos); /* patch the header size fields */ cur_pos = avio_tell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { header_size += 8 + 30 + DATA_HEADER_SIZE; avio_seek(pb, header_offset - 10 - 30, SEEK_SET); avio_wl16(pb, header_size); avio_seek(pb, header_offset - 2 - 30, SEEK_SET); avio_wl16(pb, header_size); header_size -= 8 + 30 + DATA_HEADER_SIZE; } header_size += 24 + 6; avio_seek(pb, header_offset - 14, SEEK_SET); avio_wl64(pb, header_size); avio_seek(pb, cur_pos, SEEK_SET); /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, asf->nb_packets); /* nb packets */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 1); /* ??? */ return 0; }
/* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; ByteIOContext *pb = &s->pb; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; AVCodecContext *enc; int64_t header_offset, cur_pos, hpos; int bit_rate; int64_t duration; duration = asf->duration + preroll_time * 10000; has_title = (s->title[0] || s->author[0] || s->copyright[0] || s->comment[0]); bit_rate = 0; for(n=0;n<s->nb_streams;n++) { enc = s->streams[n]->codec; av_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } put_guid(pb, &asf_header); put_le64(pb, -1); /* header length, will be patched after */ put_le32(pb, 3 + has_title + s->nb_streams); /* number of chunks in header */ put_byte(pb, 1); /* ??? */ put_byte(pb, 2); /* ??? */ /* file header */ header_offset = url_ftell(pb); hpos = put_header(pb, &file_header); put_guid(pb, &my_guid); put_le64(pb, file_size); file_time = 0; put_le64(pb, unix_to_file_time(file_time)); put_le64(pb, asf->nb_packets); /* number of packets */ put_le64(pb, duration); /* end time stamp (in 100ns units) */ put_le64(pb, duration); /* duration (in 100ns units) */ put_le32(pb, preroll_time); /* start time stamp */ put_le32(pb, 0); /* ??? */ put_le32(pb, asf->is_streamed ? 1 : 0); /* ??? */ put_le32(pb, asf->packet_size); /* packet size */ put_le32(pb, asf->packet_size); /* packet size */ put_le32(pb, bit_rate); /* Nominal data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &head1_guid); put_guid(pb, &head2_guid); put_le32(pb, 6); put_le16(pb, 0); end_header(pb, hpos); /* title and other infos */ if (has_title) { hpos = put_header(pb, &comment_header); if ( s->title[0] ) { put_le16(pb, 2 * (strlen(s->title ) + 1)); } else { put_le16(pb, 0); } if ( s->author[0] ) { put_le16(pb, 2 * (strlen(s->author ) + 1)); } else { put_le16(pb, 0); } if ( s->copyright[0] ) { put_le16(pb, 2 * (strlen(s->copyright) + 1)); } else { put_le16(pb, 0); } if ( s->comment[0] ) { put_le16(pb, 2 * (strlen(s->comment ) + 1)); } else { put_le16(pb, 0); } put_le16(pb, 0); if ( s->title[0] ) put_str16_nolen(pb, s->title); if ( s->author[0] ) put_str16_nolen(pb, s->author); if ( s->copyright[0] ) put_str16_nolen(pb, s->copyright); if ( s->comment[0] ) put_str16_nolen(pb, s->comment); end_header(pb, hpos); } /* stream headers */ for(n=0;n<s->nb_streams;n++) { int64_t es_pos; const uint8_t *er_spr = NULL; int er_spr_len = 0; // ASFStream *stream = &asf->streams[n]; enc = s->streams[n]->codec; asf->streams[n].num = n + 1; asf->streams[n].seq = 0; if (enc->codec_type == CODEC_TYPE_AUDIO) { if (enc->codec_id == CODEC_ID_ADPCM_G726) { er_spr = error_spread_ADPCM_G726; er_spr_len = sizeof(error_spread_ADPCM_G726); } } switch(enc->codec_type) { case CODEC_TYPE_AUDIO: wav_extra_size = 0; extra_size = 18 + wav_extra_size; extra_size2 = er_spr_len; break; default: case CODEC_TYPE_VIDEO: wav_extra_size = enc->extradata_size; extra_size = 0x33 + wav_extra_size; extra_size2 = 0; break; } hpos = put_header(pb, &stream_header); if (enc->codec_type == CODEC_TYPE_AUDIO) { put_guid(pb, &audio_stream); if ((er_spr != NULL) && (er_spr_len != 0)) { put_guid(pb, &audio_conceal_spread); } else { put_guid(pb, &video_conceal_none); } } else { put_guid(pb, &video_stream); put_guid(pb, &video_conceal_none); } put_le64(pb, 0); /* ??? */ es_pos = url_ftell(pb); put_le32(pb, extra_size); /* wav header len */ put_le32(pb, extra_size2); /* additional data len */ put_le16(pb, n + 1); /* stream number */ put_le32(pb, 0); /* ??? */ if (enc->codec_type == CODEC_TYPE_AUDIO) { /* WAVEFORMATEX header */ int wavsize = put_wav_header(pb, enc); 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)) { wavsize += 2; put_le16(pb, 0); } if (wavsize < 0) return -1; if (wavsize != extra_size) { cur_pos = url_ftell(pb); url_fseek(pb, es_pos, SEEK_SET); put_le32(pb, wavsize); /* wav header len */ url_fseek(pb, cur_pos, SEEK_SET); } /* ERROR Correction */ if ((er_spr != NULL) && (er_spr_len != 0)) put_buffer(pb, er_spr, er_spr_len); } else { put_le32(pb, enc->width); put_le32(pb, enc->height); put_byte(pb, 2); /* ??? */ put_le16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ put_bmp_header(pb, enc, codec_bmp_tags, 1); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &codec_comment_header); put_guid(pb, &codec_comment1_header); put_le32(pb, s->nb_streams); for(n=0;n<s->nb_streams;n++) { AVCodec *p; enc = s->streams[n]->codec; p = avcodec_find_encoder(enc->codec_id); put_le16(pb, asf->streams[n].num); put_str16(pb, p ? p->name : enc->codec_name); put_le16(pb, 0); /* no parameters */ /* id */ if (enc->codec_type == CODEC_TYPE_AUDIO) { put_le16(pb, 2); if(!enc->codec_tag) enc->codec_tag = codec_get_tag(codec_wav_tags, enc->codec_id); if(!enc->codec_tag) return -1; put_le16(pb, enc->codec_tag); } else { put_le16(pb, 4); if(!enc->codec_tag) enc->codec_tag = codec_get_tag(codec_bmp_tags, enc->codec_id); if(!enc->codec_tag) return -1; put_le32(pb, enc->codec_tag); } } end_header(pb, hpos); /* patch the header size fields */ cur_pos = url_ftell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { header_size += 8 + 30 + 50; url_fseek(pb, header_offset - 10 - 30, SEEK_SET); put_le16(pb, header_size); url_fseek(pb, header_offset - 2 - 30, SEEK_SET); put_le16(pb, header_size); header_size -= 8 + 30 + 50; } header_size += 24 + 6; url_fseek(pb, header_offset - 14, SEEK_SET); put_le64(pb, header_size); url_fseek(pb, cur_pos, SEEK_SET); /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; put_guid(pb, &data_header); put_le64(pb, data_chunk_size); put_guid(pb, &my_guid); put_le64(pb, asf->nb_packets); /* nb packets */ put_byte(pb, 1); /* ??? */ put_byte(pb, 1); /* ??? */ return 0; }