static void mms_put_utf16(MMSContext *mms, uint8_t *src) { AVIOContext bic; int size = mms->write_out_ptr - mms->out_buffer; int len; ffio_init_context(&bic, mms->write_out_ptr, sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL); len = avio_put_str16le(&bic, src); mms->write_out_ptr += len; }
static void put_str16(AVIOContext *s, const char *tag) { int len; uint8_t *pb; AVIOContext *dyn_buf; if (avio_open_dyn_buf(&dyn_buf) < 0) return; avio_put_str16le(dyn_buf, tag); len = avio_close_dyn_buf(dyn_buf, &pb); avio_wl16(s, len); avio_write(s, pb, len); av_freep(&pb); }
static int mms_put_utf16(MMSContext *mms, const uint8_t *src) { AVIOContext bic; int size = mms->write_out_ptr - mms->out_buffer; int len; ffio_init_context(&bic, mms->write_out_ptr, sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL); len = avio_put_str16le(&bic, src); if (len < 0) return len; mms->write_out_ptr += len; return 0; }
static void put_str16(ByteIOContext *s, const char *tag) { int len; uint8_t *pb; ByteIOContext *dyn_buf; if (url_open_dyn_buf(&dyn_buf) < 0) return; avio_put_str16le(dyn_buf, tag); len = url_close_dyn_buf(dyn_buf, &pb); put_le16(s, len); put_buffer(s, pb, len); av_freep(&pb); }
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); ff_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; AVIOContext *pb = s->pb; AVDictionaryEntry *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title, has_aspect_ratio = 0; 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_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); 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++) { enc = s->streams[n]->codec; avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */ bit_rate += enc->bit_rate; if ( enc->codec_type == AVMEDIA_TYPE_VIDEO && enc->sample_aspect_ratio.num > 0 && enc->sample_aspect_ratio.den > 0) has_aspect_ratio++; } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } ff_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); ff_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 ? bit_rate : -1); /* Maximum data rate in bps */ end_header(pb, hpos); /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); ff_put_guid(pb, &ff_asf_head2_guid); avio_wl16(pb, 6); if (has_aspect_ratio) { int64_t hpos2; avio_wl32(pb, 26 + has_aspect_ratio * 84); hpos2 = put_header(pb, &ff_asf_metadata_header); avio_wl16(pb, 2 * has_aspect_ratio); for (n = 0; n < s->nb_streams; n++) { enc = s->streams[n]->codec; if ( enc->codec_type == AVMEDIA_TYPE_VIDEO && enc->sample_aspect_ratio.num > 0 && enc->sample_aspect_ratio.den > 0) { AVRational sar = enc->sample_aspect_ratio; avio_wl16(pb, 0); // the stream number is set like this below avio_wl16(pb, n + 1); avio_wl16(pb, 26); // name_len avio_wl16(pb, 3); // value_type avio_wl32(pb, 4); // value_len avio_put_str16le(pb, "AspectRatioX"); avio_wl32(pb, sar.num); avio_wl16(pb, 0); // the stream number is set like this below avio_wl16(pb, n + 1); avio_wl16(pb, 26); // name_len avio_wl16(pb, 3); // value_type avio_wl32(pb, 4); // value_len avio_put_str16le(pb, "AspectRatioY"); avio_wl32(pb, sar.den); } } end_header(pb, hpos2); } else { avio_wl32(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) { 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]; enc = s->streams[n]->codec; asf->streams[n].num = n + 1; asf->streams[n].seq = 1; 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) { ff_put_guid(pb, &ff_asf_audio_stream); ff_put_guid(pb, &ff_asf_audio_conceal_spread); } else { ff_put_guid(pb, &ff_asf_video_stream); ff_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, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); 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 == AV_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, 0); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); ff_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; enc = s->streams[n]->codec; codec_desc = avcodec_descriptor_get(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 == 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 (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 + 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; ff_put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); ff_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; 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); 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, s->packet_size); /* packet size */ put_le32(pb, s->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) { int len; uint8_t *buf; ByteIOContext *dyn_buf; if (url_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; put_le16(pb, len); } len = url_close_dyn_buf(dyn_buf, &buf); put_buffer(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); put_le16(pb, metadata_count); while ((tag = av_metadata_get(s->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX))) { put_str16(pb, tag->key); put_le16(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); } 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 == 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; 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 */ 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); put_le32(pb, s->nb_streams); for(n=0;n<s->nb_streams;n++) { AVCodec *p; const char *desc; int len; uint8_t *buf; ByteIOContext *dyn_buf; enc = s->streams[n]->codec; p = avcodec_find_encoder(enc->codec_id); if(enc->codec_type == AVMEDIA_TYPE_AUDIO) put_le16(pb, 2); else if(enc->codec_type == AVMEDIA_TYPE_VIDEO) put_le16(pb, 1); else put_le16(pb, -1); if(enc->codec_id == CODEC_ID_WMAV2) desc = "Windows Media Audio V8"; else desc = p ? p->name : enc->codec_name; if ( url_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); avio_put_str16le(dyn_buf, desc); len = url_close_dyn_buf(dyn_buf, &buf); put_le16(pb, len / 2); // "number of characters" = length in bytes / 2 put_buffer(pb, buf, len); av_freep(&buf); put_le16(pb, 0); /* no parameters */ /* id */ if (enc->codec_type == AVMEDIA_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; AVDictionaryEntry *tags[5]; int header_size, n, extra_size, extra_size2, wav_extra_size; int has_title, has_aspect_ratio = 0; int metadata_count; AVCodecParameters *par; int64_t header_offset, cur_pos, hpos; int bit_rate; int64_t duration; int audio_language_counts[128] = { 0 }; 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); duration = asf->duration + PREROLL_TIME * 10000; has_title = tags[0] || tags[1] || tags[2] || tags[3] || tags[4]; if (!file_size) { if (ff_parse_creation_time_metadata(s, &asf->creation_time, 0) != 0) av_dict_set(&s->metadata, "creation_time", NULL, 0); } metadata_count = av_dict_count(s->metadata); bit_rate = 0; for (n = 0; n < s->nb_streams; n++) { AVDictionaryEntry *entry; 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 ( par->codec_type == AVMEDIA_TYPE_VIDEO && par->sample_aspect_ratio.num > 0 && par->sample_aspect_ratio.den > 0) has_aspect_ratio++; entry = av_dict_get(s->streams[n]->metadata, "language", NULL, 0); if (entry) { const char *iso6391lang = ff_convert_lang_to(entry->value, AV_LANG_ISO639_1); if (iso6391lang) { int i; for (i = 0; i < asf->nb_languages; i++) { if (!strcmp(asf->languages[i], iso6391lang)) { asf->streams[n].stream_language_index = i; break; } } if (i >= asf->nb_languages) { asf->languages[asf->nb_languages] = iso6391lang; asf->streams[n].stream_language_index = asf->nb_languages; asf->nb_languages++; } if (par->codec_type == AVMEDIA_TYPE_AUDIO) audio_language_counts[asf->streams[n].stream_language_index]++; } } else { asf->streams[n].stream_language_index = 128; } } if (asf->is_streamed) { put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } ff_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); ff_put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, file_size); avio_wl64(pb, unix_to_file_time(asf->creation_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 ? bit_rate : -1); /* Maximum data rate in bps */ end_header(pb, hpos); /* header_extension */ hpos = put_header(pb, &ff_asf_head1_guid); ff_put_guid(pb, &ff_asf_head2_guid); avio_wl16(pb, 6); avio_wl32(pb, 0); /* length, to be filled later */ if (asf->nb_languages) { int64_t hpos2; int i; int nb_audio_languages = 0; hpos2 = put_header(pb, &ff_asf_language_guid); avio_wl16(pb, asf->nb_languages); for (i = 0; i < asf->nb_languages; i++) { avio_w8(pb, 6); avio_put_str16le(pb, asf->languages[i]); } end_header(pb, hpos2); for (i = 0; i < asf->nb_languages; i++) if (audio_language_counts[i]) nb_audio_languages++; if (nb_audio_languages > 1) { hpos2 = put_header(pb, &ff_asf_group_mutual_exclusion_object); ff_put_guid(pb, &ff_asf_mutex_language); avio_wl16(pb, nb_audio_languages); for (i = 0; i < asf->nb_languages; i++) { if (audio_language_counts[i]) { avio_wl16(pb, audio_language_counts[i]); for (n = 0; n < s->nb_streams; n++) if (asf->streams[n].stream_language_index == i && s->streams[n]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl16(pb, n + 1); } } end_header(pb, hpos2); } for (n = 0; n < s->nb_streams; n++) { int64_t es_pos; if (asf->streams[n].stream_language_index > 127) continue; es_pos = put_header(pb, &ff_asf_extended_stream_properties_object); avio_wl64(pb, 0); /* start time */ avio_wl64(pb, 0); /* end time */ avio_wl32(pb, s->streams[n]->codecpar->bit_rate); /* data bitrate bps */ avio_wl32(pb, 5000); /* buffer size ms */ avio_wl32(pb, 0); /* initial buffer fullness */ avio_wl32(pb, s->streams[n]->codecpar->bit_rate); /* peak data bitrate */ avio_wl32(pb, 5000); /* maximum buffer size ms */ avio_wl32(pb, 0); /* max initial buffer fullness */ avio_wl32(pb, 0); /* max object size */ avio_wl32(pb, (!asf->is_streamed && pb->seekable) << 1); /* flags - seekable */ avio_wl16(pb, n + 1); /* stream number */ avio_wl16(pb, asf->streams[n].stream_language_index); /* language id index */ avio_wl64(pb, 0); /* avg time per frame */ avio_wl16(pb, 0); /* stream name count */ avio_wl16(pb, 0); /* payload extension system count */ end_header(pb, es_pos); } } if (has_aspect_ratio) { int64_t hpos2; hpos2 = put_header(pb, &ff_asf_metadata_header); avio_wl16(pb, 2 * has_aspect_ratio); for (n = 0; n < s->nb_streams; n++) { par = s->streams[n]->codecpar; if ( par->codec_type == AVMEDIA_TYPE_VIDEO && par->sample_aspect_ratio.num > 0 && par->sample_aspect_ratio.den > 0) { AVRational sar = par->sample_aspect_ratio; avio_wl16(pb, 0); // the stream number is set like this below avio_wl16(pb, n + 1); avio_wl16(pb, 26); // name_len avio_wl16(pb, 3); // value_type avio_wl32(pb, 4); // value_len avio_put_str16le(pb, "AspectRatioX"); avio_wl32(pb, sar.num); avio_wl16(pb, 0); // the stream number is set like this below avio_wl16(pb, n + 1); avio_wl16(pb, 26); // name_len avio_wl16(pb, 3); // value_type avio_wl32(pb, 4); // value_len avio_put_str16le(pb, "AspectRatioY"); avio_wl32(pb, sar.den); } } end_header(pb, hpos2); } { int64_t pos1; pos1 = avio_tell(pb); avio_seek(pb, hpos + 42, SEEK_SET); avio_wl32(pb, pos1 - hpos - 46); avio_seek(pb, pos1, SEEK_SET); } 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)) < 0) 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 = 1; 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) { ff_put_guid(pb, &ff_asf_audio_stream); ff_put_guid(pb, &ff_asf_audio_conceal_spread); } else { ff_put_guid(pb, &ff_asf_video_stream); ff_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, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); 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, 0); } end_header(pb, hpos); } /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); ff_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; ff_put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); ff_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; }