static int wav_write_header(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVIOContext *pb = s->pb; int64_t fmt; if (wav->rf64 == RF64_ALWAYS) { ffio_wfourcc(pb, "RF64"); avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ } else { ffio_wfourcc(pb, "RIFF"); avio_wl32(pb, 0); /* file length */ } ffio_wfourcc(pb, "WAVE"); if (wav->rf64 != RF64_NEVER) { /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */ ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK"); avio_wl32(pb, 28); /* chunk size */ wav->ds64 = avio_tell(pb); ffio_fill(pb, 0, 28); } /* format header */ fmt = ff_start_tag(pb, "fmt "); if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) { av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); return -1; } ff_end_tag(pb, fmt); if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ && s->pb->seekable) { wav->fact_pos = ff_start_tag(pb, "fact"); avio_wl32(pb, 0); ff_end_tag(pb, wav->fact_pos); } if (wav->write_bext) bwf_write_bext_chunk(s); avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); wav->maxpts = wav->last_duration = 0; wav->minpts = INT64_MAX; /* info header */ ff_riff_write_info(s); /* data header */ wav->data = ff_start_tag(pb, "data"); avio_flush(pb); return 0; }
static int mmf_write_header(AVFormatContext *s) { MMFContext *mmf = s->priv_data; AVIOContext *pb = s->pb; int64_t pos; int rate; rate = mmf_rate_code(s->streams[0]->codec->sample_rate); if (rate < 0) { av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n", s->streams[0]->codec->sample_rate); return -1; } ffio_wfourcc(pb, "MMMD"); avio_wb32(pb, 0); pos = ff_start_tag(pb, "CNTI"); avio_w8(pb, 0); /* class */ avio_w8(pb, 0); /* type */ avio_w8(pb, 0); /* code type */ avio_w8(pb, 0); /* status */ avio_w8(pb, 0); /* counts */ end_tag_be(pb, pos); pos = ff_start_tag(pb, "OPDA"); avio_write(pb, "VN:libavcodec,", sizeof("VN:libavcodec,") -1); /* metadata ("ST:songtitle,VN:version,...") */ end_tag_be(pb, pos); avio_write(pb, "ATR\x00", 4); avio_wb32(pb, 0); mmf->atrpos = avio_tell(pb); avio_w8(pb, 0); /* format type */ avio_w8(pb, 0); /* sequence type */ avio_w8(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */ avio_w8(pb, 0); /* wave base bit */ avio_w8(pb, 2); /* time base d */ avio_w8(pb, 2); /* time base g */ ffio_wfourcc(pb, "Atsq"); avio_wb32(pb, 16); mmf->atsqpos = avio_tell(pb); /* Will be filled on close */ avio_write(pb, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16); mmf->awapos = ff_start_tag(pb, "Awa\x01"); avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); avio_flush(pb); return 0; }
static void write_odml_master(AVFormatContext *s, int stream_index) { AVIOContext *pb = s->pb; AVStream *st = s->streams[stream_index]; AVCodecContext *enc = st->codec; AVIStream *avist = st->priv_data; unsigned char tag[5]; int j; /* Starting to lay out AVI OpenDML master index. * We want to make it JUNK entry for now, since we'd * like to get away without making AVI an OpenDML one * for compatibility reasons. */ avist->indexes.indx_start = ff_start_tag(pb, "JUNK"); avio_wl16(pb, 4); /* wLongsPerEntry */ avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */ ffio_wfourcc(pb, avi_stream2fourcc(tag, stream_index, enc->codec_type)); /* dwChunkId */ avio_wl64(pb, 0); /* dwReserved[3] */ avio_wl32(pb, 0); /* Must be 0. */ for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++) avio_wl64(pb, 0); ff_end_tag(pb, avist->indexes.indx_start); }
static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb, const char* riff_tag, const char* list_tag) { AVIContext *avi= s->priv_data; int64_t loff; int i; avi->riff_id++; for (i=0; i<s->nb_streams; i++){ AVIStream *avist= s->streams[i]->priv_data; avist->indexes.entry = 0; } avi->riff_start = ff_start_tag(pb, "RIFF"); ffio_wfourcc(pb, riff_tag); loff = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, list_tag); return loff; }
static int wav_write_header(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVIOContext *pb = s->pb; int64_t fmt; ffio_wfourcc(pb, "RIFF"); avio_wl32(pb, 0); /* file length */ ffio_wfourcc(pb, "WAVE"); /* format header */ fmt = ff_start_tag(pb, "fmt "); if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) { av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); return -1; } ff_end_tag(pb, fmt); if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ && s->pb->seekable) { wav->fact_pos = ff_start_tag(pb, "fact"); avio_wl32(pb, 0); ff_end_tag(pb, wav->fact_pos); } if (wav->write_bext) bwf_write_bext_chunk(s); avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); wav->maxpts = wav->last_duration = 0; wav->minpts = INT64_MAX; /* info header */ ff_riff_write_info(s); /* data header */ wav->data = ff_start_tag(pb, "data"); avio_flush(pb); return 0; }
static int wav_write_header(AVFormatContext *s) { WAVContext *wav = s->priv_data; ByteIOContext *pb = s->pb; int64_t fmt, fact; put_tag(pb, "RIFF"); put_le32(pb, 0); /* file length */ put_tag(pb, "WAVE"); /* format header */ fmt = ff_start_tag(pb, "fmt "); if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) { av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); av_free(wav); return -1; } ff_end_tag(pb, fmt); if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ && !url_is_streamed(s->pb)) { fact = ff_start_tag(pb, "fact"); put_le32(pb, 0); ff_end_tag(pb, fact); } av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); wav->maxpts = wav->last_duration = 0; wav->minpts = INT64_MAX; /* data header */ wav->data = ff_start_tag(pb, "data"); put_flush_packet(pb); return 0; }
static int avi_write_idx1(AVFormatContext *s) { AVIOContext *pb = s->pb; AVIContext *avi = s->priv_data; int64_t idx_chunk; int i; char tag[5]; if (pb->seekable) { AVIStream *avist; AVIIentry* ie = 0, *tie; int empty, stream_id = -1; idx_chunk = ff_start_tag(pb, "idx1"); for(i=0; i<s->nb_streams; i++){ avist= s->streams[i]->priv_data; avist->entry=0; } do { empty = 1; for (i=0; i<s->nb_streams; i++) { avist= s->streams[i]->priv_data; if (avist->indexes.entry <= avist->entry) continue; tie = avi_get_ientry(&avist->indexes, avist->entry); if (empty || tie->pos < ie->pos) { ie = tie; stream_id = i; } empty = 0; } if (!empty) { avist= s->streams[stream_id]->priv_data; avi_stream2fourcc(tag, stream_id, s->streams[stream_id]->codec->codec_type); ffio_wfourcc(pb, tag); avio_wl32(pb, ie->flags); avio_wl32(pb, ie->pos); avio_wl32(pb, ie->len); avist->entry++; } } while (!empty); ff_end_tag(pb, idx_chunk); avi_write_counters(s, avi->riff_id); } return 0; }
static int peak_write_chunk(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVIOContext *pb = s->pb; AVCodecContext *enc = s->streams[0]->codec; int64_t peak = ff_start_tag(s->pb, "levl"); int64_t now0; time_t now_secs; char timestamp[28]; /* Peak frame of incomplete block at end */ if (wav->peak_block_pos) peak_write_frame(s); memset(timestamp, 0, sizeof(timestamp)); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { struct tm tmpbuf; av_log(s, AV_LOG_INFO, "Writing local time and date to Peak Envelope Chunk\n"); now0 = av_gettime(); now_secs = now0 / 1000000; if (strftime(timestamp, sizeof(timestamp), "%Y:%m:%d:%H:%M:%S:", localtime_r(&now_secs, &tmpbuf))) { av_strlcatf(timestamp, sizeof(timestamp), "%03d", (int)((now0 / 1000) % 1000)); } else { av_log(s, AV_LOG_ERROR, "Failed to write timestamp\n"); return -1; } } avio_wl32(pb, 1); /* version */ avio_wl32(pb, wav->peak_format); /* 8 or 16 bit */ avio_wl32(pb, wav->peak_ppv); /* positive and negative */ avio_wl32(pb, wav->peak_block_size); /* frames per value */ avio_wl32(pb, enc->channels); /* number of channels */ avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */ avio_wl32(pb, wav->peak_pos_pop); /* audio sample frame index */ avio_wl32(pb, 128); /* equal to size of header */ avio_write(pb, timestamp, 28); /* ASCII time stamp */ ffio_fill(pb, 0, 60); avio_write(pb, wav->peak_output, wav->peak_outbuf_bytes); ff_end_tag(pb, peak); if (!wav->data) wav->data = peak; return 0; }
void ff_riff_write_info(AVFormatContext *s) { AVIOContext *pb = s->pb; int i; int64_t list_pos; AVDictionaryEntry *t = NULL; ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL); /* writing empty LIST is not nice and may cause problems */ if (!riff_has_valid_tags(s)) return; list_pos = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "INFO"); for (i = 0; *riff_tags[i]; i++) if ((t = av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE))) ff_riff_write_info_tag(s->pb, t->key, t->value); ff_end_tag(pb, list_pos); }
static void bwf_write_bext_chunk(AVFormatContext *s) { AVDictionaryEntry *tmp_tag; uint64_t time_reference = 0; int64_t bext = ff_start_tag(s->pb, "bext"); bwf_write_bext_string(s, "description", 256); bwf_write_bext_string(s, "originator", 32); bwf_write_bext_string(s, "originator_reference", 32); bwf_write_bext_string(s, "origination_date", 10); bwf_write_bext_string(s, "origination_time", 8); if (tmp_tag = av_dict_get(s->metadata, "time_reference", NULL, 0)) time_reference = strtoll(tmp_tag->value, NULL, 10); avio_wl64(s->pb, time_reference); avio_wl16(s->pb, 1); // set version to 1 if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) { unsigned char umidpart_str[17] = {0}; int i; uint64_t umidpart; int len = strlen(tmp_tag->value+2); for (i = 0; i < len/16; i++) { memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16); umidpart = strtoll(umidpart_str, NULL, 16); avio_wb64(s->pb, umidpart); } ffio_fill(s->pb, 0, 64 - i*8); } else ffio_fill(s->pb, 0, 64); // zero UMID ffio_fill(s->pb, 0, 190); // Reserved if (tmp_tag = av_dict_get(s->metadata, "coding_history", NULL, 0)) avio_put_str(s->pb, tmp_tag->value); ff_end_tag(s->pb, bext); }
static int avi_write_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream, *video_enc; int64_t list1, list2, strh, strf; AVDictionaryEntry *t = NULL; if (s->nb_streams > AVI_MAX_STREAM_COUNT) { av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n", AVI_MAX_STREAM_COUNT); return AVERROR(EINVAL); } for(n=0;n<s->nb_streams;n++) { s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream)); if(!s->streams[n]->priv_data) return AVERROR(ENOMEM); } /* header list */ avi->riff_id = 0; list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl"); /* avi header */ ffio_wfourcc(pb, "avih"); avio_wl32(pb, 14 * 4); bitrate = 0; video_enc = NULL; for(n=0;n<s->nb_streams;n++) { stream = s->streams[n]->codec; bitrate += stream->bit_rate; if (stream->codec_type == AVMEDIA_TYPE_VIDEO) video_enc = stream; } nb_frames = 0; if(video_enc){ avio_wl32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); } else { avio_wl32(pb, 0); } avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */ avio_wl32(pb, 0); /* padding */ if (!pb->seekable) avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ else avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */ avio_wl32(pb, nb_frames); /* nb frames, filled later */ avio_wl32(pb, 0); /* initial frame */ avio_wl32(pb, s->nb_streams); /* nb streams */ avio_wl32(pb, 1024 * 1024); /* suggested buffer size */ if(video_enc){ avio_wl32(pb, video_enc->width); avio_wl32(pb, video_enc->height); } else { avio_wl32(pb, 0); avio_wl32(pb, 0); } avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ /* stream list */ for(i=0;i<n;i++) { AVIStream *avist= s->streams[i]->priv_data; list2 = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "strl"); stream = s->streams[i]->codec; /* stream generic header */ strh = ff_start_tag(pb, "strh"); switch(stream->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (stream->codec_id != AV_CODEC_ID_XSUB) { av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n"); return AVERROR_PATCHWELCOME; } case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break; case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break; // case AVMEDIA_TYPE_TEXT : ffio_wfourcc(pb, "txts"); break; case AVMEDIA_TYPE_DATA : ffio_wfourcc(pb, "dats"); break; } if(stream->codec_type == AVMEDIA_TYPE_VIDEO || stream->codec_id == AV_CODEC_ID_XSUB) avio_wl32(pb, stream->codec_tag); else avio_wl32(pb, 1); avio_wl32(pb, 0); /* flags */ avio_wl16(pb, 0); /* priority */ avio_wl16(pb, 0); /* language */ avio_wl32(pb, 0); /* initial frame */ ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); if ( stream->codec_type == AVMEDIA_TYPE_VIDEO && stream->codec_id != AV_CODEC_ID_XSUB && au_byterate > 1000LL*au_scale) { au_byterate = 600; au_scale = 1; } avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate); if(stream->codec_id == AV_CODEC_ID_XSUB) au_scale = au_byterate = 0; avio_wl32(pb, au_scale); /* scale */ avio_wl32(pb, au_byterate); /* rate */ avio_wl32(pb, 0); /* start */ avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */ if (!pb->seekable) avio_wl32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ else avio_wl32(pb, 0); /* length, XXX: filled later */ /* suggested buffer size */ //FIXME set at the end to largest chunk if(stream->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl32(pb, 1024 * 1024); else if(stream->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl32(pb, 12 * 1024); else avio_wl32(pb, 0); avio_wl32(pb, -1); /* quality */ avio_wl32(pb, au_ssize); /* sample size */ avio_wl32(pb, 0); avio_wl16(pb, stream->width); avio_wl16(pb, stream->height); ff_end_tag(pb, strh); if(stream->codec_type != AVMEDIA_TYPE_DATA){ int ret; strf = ff_start_tag(pb, "strf"); switch(stream->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (stream->codec_id != AV_CODEC_ID_XSUB) break; case AVMEDIA_TYPE_VIDEO: ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0); break; case AVMEDIA_TYPE_AUDIO: if ((ret = ff_put_wav_header(pb, stream)) < 0) { return ret; } break; default: av_log(s, AV_LOG_ERROR, "Invalid or not supported codec type '%s' found in the input\n", (char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?")); return AVERROR(EINVAL); } ff_end_tag(pb, strf); if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) { ff_riff_write_info_tag(s->pb, "strn", t->value); t = NULL; } if(stream->codec_id == AV_CODEC_ID_XSUB && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1); t = NULL; if (langstr) { char* str = av_asprintf("Subtitle - %s-xx;02", langstr); ff_riff_write_info_tag(s->pb, "strn", str); av_free(str); } } } if (pb->seekable) { unsigned char tag[5]; int j; /* Starting to lay out AVI OpenDML master index. * We want to make it JUNK entry for now, since we'd * like to get away without making AVI an OpenDML one * for compatibility reasons. */ avist->indexes.entry = avist->indexes.ents_allocated = 0; avist->indexes.indx_start = ff_start_tag(pb, "JUNK"); avio_wl16(pb, 4); /* wLongsPerEntry */ avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */ avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */ ffio_wfourcc(pb, avi_stream2fourcc(tag, i, stream->codec_type)); /* dwChunkId */ avio_wl64(pb, 0); /* dwReserved[3] avio_wl32(pb, 0); Must be 0. */ for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) avio_wl64(pb, 0); ff_end_tag(pb, avist->indexes.indx_start); } if( stream->codec_type == AVMEDIA_TYPE_VIDEO && s->streams[i]->sample_aspect_ratio.num>0 && s->streams[i]->sample_aspect_ratio.den>0){ int vprp= ff_start_tag(pb, "vprp"); AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, (AVRational){stream->width, stream->height}); int num, den; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); avio_wl32(pb, 0); //video format = unknown avio_wl32(pb, 0); //video standard= unknown avio_wl32(pb, lrintf(1.0/av_q2d(stream->time_base))); avio_wl32(pb, stream->width ); avio_wl32(pb, stream->height); avio_wl16(pb, den); avio_wl16(pb, num); avio_wl32(pb, stream->width ); avio_wl32(pb, stream->height); avio_wl32(pb, 1); //progressive FIXME avio_wl32(pb, stream->height); avio_wl32(pb, stream->width ); avio_wl32(pb, stream->height); avio_wl32(pb, stream->width ); avio_wl32(pb, 0); avio_wl32(pb, 0); avio_wl32(pb, 0); avio_wl32(pb, 0); ff_end_tag(pb, vprp); } ff_end_tag(pb, list2); } if (pb->seekable) { /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ avi->odml_list = ff_start_tag(pb, "JUNK"); ffio_wfourcc(pb, "odml"); ffio_wfourcc(pb, "dmlh"); avio_wl32(pb, 248); for (i = 0; i < 248; i+= 4) avio_wl32(pb, 0); ff_end_tag(pb, avi->odml_list); } ff_end_tag(pb, list1); ff_riff_write_info(s); /* some padding for easier tag editing */ list2 = ff_start_tag(pb, "JUNK"); for (i = 0; i < 1016; i += 4) avio_wl32(pb, 0); ff_end_tag(pb, list2); avi->movi_list = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "movi"); avio_flush(pb); return 0; }
static int wav_write_header(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVIOContext *pb = s->pb; int64_t fmt; if (s->nb_streams != 1) { av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n"); return AVERROR(EINVAL); } if (wav->rf64 == RF64_ALWAYS) { ffio_wfourcc(pb, "RF64"); avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ } else { ffio_wfourcc(pb, "RIFF"); avio_wl32(pb, -1); /* file length */ } ffio_wfourcc(pb, "WAVE"); if (wav->rf64 != RF64_NEVER) { /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */ ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK"); avio_wl32(pb, 28); /* chunk size */ wav->ds64 = avio_tell(pb); ffio_fill(pb, 0, 28); } if (wav->write_peak != 2) { /* format header */ fmt = ff_start_tag(pb, "fmt "); if (ff_put_wav_header(pb, s->streams[0]->codec, 0) < 0) { const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codec->codec_id); av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", desc ? desc->name : "unknown"); return AVERROR(ENOSYS); } ff_end_tag(pb, fmt); } if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ && s->pb->seekable) { wav->fact_pos = ff_start_tag(pb, "fact"); avio_wl32(pb, 0); ff_end_tag(pb, wav->fact_pos); } if (wav->write_bext) bwf_write_bext_chunk(s); if (wav->write_peak) { int ret; if ((ret = peak_init_writer(s)) < 0) return ret; } avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); wav->maxpts = wav->last_duration = 0; wav->minpts = INT64_MAX; if (wav->write_peak != 2) { /* info header */ ff_riff_write_info(s); /* data header */ wav->data = ff_start_tag(pb, "data"); } avio_flush(pb); return 0; }
static int avi_write_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *video_enc; AVStream *video_st = NULL; int64_t list1, list2, strh, strf; AVDictionaryEntry *t = NULL; int padding; if (s->nb_streams > AVI_MAX_STREAM_COUNT) { av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n", AVI_MAX_STREAM_COUNT); return AVERROR(EINVAL); } for (n = 0; n < s->nb_streams; n++) { s->streams[n]->priv_data = av_mallocz(sizeof(AVIStream)); if (!s->streams[n]->priv_data) return AVERROR(ENOMEM); } /* header list */ avi->riff_id = 0; list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl"); /* avi header */ ffio_wfourcc(pb, "avih"); avio_wl32(pb, 14 * 4); bitrate = 0; video_enc = NULL; for (n = 0; n < s->nb_streams; n++) { AVCodecContext *codec = s->streams[n]->codec; bitrate += codec->bit_rate; if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { video_enc = codec; video_st = s->streams[n]; } } nb_frames = 0; // TODO: should be avg_frame_rate if (video_st) avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_st->time_base.num / video_st->time_base.den)); else avio_wl32(pb, 0); avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */ avio_wl32(pb, 0); /* padding */ if (!pb->seekable) avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ else avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */ avio_wl32(pb, nb_frames); /* nb frames, filled later */ avio_wl32(pb, 0); /* initial frame */ avio_wl32(pb, s->nb_streams); /* nb streams */ avio_wl32(pb, 1024 * 1024); /* suggested buffer size */ if (video_enc) { avio_wl32(pb, video_enc->width); avio_wl32(pb, video_enc->height); } else { avio_wl32(pb, 0); avio_wl32(pb, 0); } avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ /* stream list */ for (i = 0; i < n; i++) { AVStream *st = s->streams[i]; AVCodecContext *enc = st->codec; AVIStream *avist = st->priv_data; list2 = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "strl"); /* stream generic header */ strh = ff_start_tag(pb, "strh"); switch (enc->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (enc->codec_id != AV_CODEC_ID_XSUB) { av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n"); return AVERROR_PATCHWELCOME; } case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break; case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break; // case AVMEDIA_TYPE_TEXT: // ffio_wfourcc(pb, "txts"); // break; case AVMEDIA_TYPE_DATA: ffio_wfourcc(pb, "dats"); break; } if (enc->codec_type == AVMEDIA_TYPE_VIDEO || enc->codec_id == AV_CODEC_ID_XSUB) avio_wl32(pb, enc->codec_tag); else avio_wl32(pb, 1); avio_wl32(pb, 0); /* flags */ avio_wl16(pb, 0); /* priority */ avio_wl16(pb, 0); /* language */ avio_wl32(pb, 0); /* initial frame */ ff_parse_specific_params(st, &au_byterate, &au_ssize, &au_scale); if ( enc->codec_type == AVMEDIA_TYPE_VIDEO && enc->codec_id != AV_CODEC_ID_XSUB && au_byterate > 1000LL*au_scale) { au_byterate = 600; au_scale = 1; } avpriv_set_pts_info(st, 64, au_scale, au_byterate); if (enc->codec_id == AV_CODEC_ID_XSUB) au_scale = au_byterate = 0; avio_wl32(pb, au_scale); /* scale */ avio_wl32(pb, au_byterate); /* rate */ avio_wl32(pb, 0); /* start */ /* remember this offset to fill later */ avist->frames_hdr_strm = avio_tell(pb); if (!pb->seekable) /* FIXME: this may be broken, but who cares */ avio_wl32(pb, AVI_MAX_RIFF_SIZE); else avio_wl32(pb, 0); /* length, XXX: filled later */ /* suggested buffer size, is set to largest chunk size in avi_write_trailer */ if (enc->codec_type == AVMEDIA_TYPE_VIDEO) avio_wl32(pb, 1024 * 1024); else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_wl32(pb, 12 * 1024); else avio_wl32(pb, 0); avio_wl32(pb, -1); /* quality */ avio_wl32(pb, au_ssize); /* sample size */ avio_wl32(pb, 0); avio_wl16(pb, enc->width); avio_wl16(pb, enc->height); ff_end_tag(pb, strh); if (enc->codec_type != AVMEDIA_TYPE_DATA) { int ret; enum AVPixelFormat pix_fmt; strf = ff_start_tag(pb, "strf"); switch (enc->codec_type) { case AVMEDIA_TYPE_SUBTITLE: /* XSUB subtitles behave like video tracks, other subtitles * are not (yet) supported. */ if (enc->codec_id != AV_CODEC_ID_XSUB) break; case AVMEDIA_TYPE_VIDEO: /* WMP expects RGB 5:5:5 rawvideo in avi to have bpp set to 16. */ if ( !enc->codec_tag && enc->codec_id == AV_CODEC_ID_RAWVIDEO && enc->pix_fmt == AV_PIX_FMT_RGB555LE && enc->bits_per_coded_sample == 15) enc->bits_per_coded_sample = 16; ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 0, 0); pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi, enc->bits_per_coded_sample); if ( !enc->codec_tag && enc->codec_id == AV_CODEC_ID_RAWVIDEO && enc->pix_fmt != pix_fmt && enc->pix_fmt != AV_PIX_FMT_NONE) av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to avi, output file will be unreadable\n", av_get_pix_fmt_name(enc->pix_fmt)); break; case AVMEDIA_TYPE_AUDIO: if ((ret = ff_put_wav_header(pb, enc, 0)) < 0) return ret; break; default: av_log(s, AV_LOG_ERROR, "Invalid or not supported codec type '%s' found in the input\n", (char *)av_x_if_null(av_get_media_type_string(enc->codec_type), "?")); return AVERROR(EINVAL); } ff_end_tag(pb, strf); if ((t = av_dict_get(st->metadata, "title", NULL, 0))) { ff_riff_write_info_tag(s->pb, "strn", t->value); t = NULL; } if (enc->codec_id == AV_CODEC_ID_XSUB && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1); t = NULL; if (langstr) { char* str = av_asprintf("Subtitle - %s-xx;02", langstr); if (!str) return AVERROR(ENOMEM); ff_riff_write_info_tag(s->pb, "strn", str); av_free(str); } } } if (pb->seekable) { write_odml_master(s, i); } if (enc->codec_type == AVMEDIA_TYPE_VIDEO && st->sample_aspect_ratio.num > 0 && st->sample_aspect_ratio.den > 0) { int vprp = ff_start_tag(pb, "vprp"); AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational) { enc->width, enc->height }); int num, den; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); avio_wl32(pb, 0); // video format = unknown avio_wl32(pb, 0); // video standard = unknown // TODO: should be avg_frame_rate avio_wl32(pb, (2LL*st->time_base.den + st->time_base.num - 1) / (2LL * st->time_base.num)); avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_wl16(pb, den); avio_wl16(pb, num); avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_wl32(pb, 1); // progressive FIXME avio_wl32(pb, enc->height); avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_wl32(pb, enc->width); avio_wl32(pb, 0); avio_wl32(pb, 0); avio_wl32(pb, 0); avio_wl32(pb, 0); ff_end_tag(pb, vprp); } ff_end_tag(pb, list2); } if (pb->seekable) { /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ avi->odml_list = ff_start_tag(pb, "JUNK"); ffio_wfourcc(pb, "odml"); ffio_wfourcc(pb, "dmlh"); avio_wl32(pb, 248); for (i = 0; i < 248; i += 4) avio_wl32(pb, 0); ff_end_tag(pb, avi->odml_list); } ff_end_tag(pb, list1); ff_riff_write_info(s); padding = s->metadata_header_padding; if (padding < 0) padding = 1016; /* some padding for easier tag editing */ if (padding) { list2 = ff_start_tag(pb, "JUNK"); for (i = padding; i > 0; i -= 4) avio_wl32(pb, 0); ff_end_tag(pb, list2); } avi->movi_list = ff_start_tag(pb, "LIST"); ffio_wfourcc(pb, "movi"); avio_flush(pb); return 0; }