diff --git a/libav/avienc.c b/libav/avienc.c index c971ef03ae..b894fd7280 100644 --- a/libav/avienc.c +++ b/libav/avienc.c @@ -31,7 +31,8 @@ typedef struct AVIIndex { } AVIIndex; typedef struct { - offset_t movi_list; + offset_t movi_list, frames_hdr_all, frames_hdr_strm[MAX_STREAMS]; + int audio_strm_length[MAX_STREAMS]; AVIIndex *first, *last; } AVIContext; @@ -109,11 +110,36 @@ void put_bmp_header(ByteIOContext *pb, AVCodecContext *enc) put_le32(pb, 0); } +void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale) +{ + switch(stream->codec_id) { + case CODEC_ID_PCM_S16LE: + *au_scale = *au_ssize = 2*stream->channels; + *au_byterate = *au_ssize * stream->sample_rate; + break; + case CODEC_ID_PCM_U8: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_MULAW: + *au_scale = *au_ssize = stream->channels; + *au_byterate = *au_ssize * stream->sample_rate; + break; + case CODEC_ID_MP2: + *au_ssize = 1; + *au_scale = 1; + *au_byterate = stream->bit_rate / 8; + default: + *au_ssize = 1; + *au_scale = 1; + *au_byterate = stream->bit_rate / 8; + break; + } +} + static int avi_write_header(AVFormatContext *s) { AVIContext *avi; ByteIOContext *pb = &s->pb; - int bitrate, n, i, nb_frames; + int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream, *video_enc; offset_t list1, list2, strh, strf; @@ -154,6 +180,7 @@ static int avi_write_header(AVFormatContext *s) put_le32(pb, bitrate / 8); /* XXX: not quite exact */ put_le32(pb, 0); /* padding */ put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ + avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ put_le32(pb, nb_frames); /* nb frames, filled later */ put_le32(pb, 0); /* initial frame */ put_le32(pb, s->nb_streams); /* nb streams */ @@ -185,9 +212,10 @@ static int avi_write_header(AVFormatContext *s) put_le32(pb, 1000); /* scale */ put_le32(pb, (1000 * stream->frame_rate) / FRAME_RATE_BASE); /* rate */ put_le32(pb, 0); /* start */ + avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ put_le32(pb, nb_frames); /* length, XXX: fill later */ put_le32(pb, 1024 * 1024); /* suggested buffer size */ - put_le32(pb, 10000); /* quality */ + put_le32(pb, -1); /* quality */ put_le32(pb, stream->width * stream->height * 3); /* sample size */ put_le16(pb, 0); put_le16(pb, 0); @@ -196,18 +224,20 @@ static int avi_write_header(AVFormatContext *s) break; case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); - put_le32(pb, 0); + put_le32(pb, 1); /* tag */ put_le32(pb, 0); /* flags */ put_le16(pb, 0); /* priority */ put_le16(pb, 0); /* language */ put_le32(pb, 0); /* initial frame */ - put_le32(pb, 1); /* scale */ - put_le32(pb, stream->bit_rate / 8); /* rate */ + parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); + put_le32(pb, au_scale); /* scale */ + put_le32(pb, au_byterate); /* rate */ put_le32(pb, 0); /* start */ + avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ put_le32(pb, 0); /* length, XXX: filled later */ put_le32(pb, 12 * 1024); /* suggested buffer size */ put_le32(pb, -1); /* quality */ - put_le32(pb, 1); /* sample size */ + put_le32(pb, au_ssize); /* sample size */ put_le32(pb, 0); put_le32(pb, 0); break; @@ -265,6 +295,8 @@ static int avi_write_packet(AVFormatContext *s, int stream_index, tag[3] = 'b'; flags = 0x10; } + if (enc->codec_type == CODEC_TYPE_AUDIO) + avi->audio_strm_length[stream_index] += size; if (!url_is_streamed(&s->pb)) { idx = malloc(sizeof(AVIIndex)); @@ -295,6 +327,8 @@ static int avi_write_trailer(AVFormatContext *s) ByteIOContext *pb = &s->pb; AVIContext *avi = s->priv_data; offset_t file_size, idx_chunk; + int n, nb_frames, au_byterate, au_ssize, au_scale; + AVCodecContext *stream; AVIIndex *idx; if (!url_is_streamed(&s->pb)) { @@ -315,6 +349,32 @@ static int avi_write_trailer(AVFormatContext *s) file_size = url_ftell(pb); url_fseek(pb, 4, SEEK_SET); put_le32(pb, (UINT32)(file_size - 8)); + + /* Fill in frame/sample counters */ + nb_frames = 0; + for(n=0;nnb_streams;n++) { + if (avi->frames_hdr_strm[n] != 0) { + stream = &s->streams[n]->codec; + url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); + if (stream->codec_type == CODEC_TYPE_VIDEO) { + put_le32(pb, stream->frame_number); + if (nb_frames < stream->frame_number) + nb_frames = stream->frame_number; + } else { + if (stream->codec_id == CODEC_ID_MP2) { + put_le32(pb, stream->frame_number); + nb_frames += stream->frame_number; + } else { + parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); + put_le32(pb, avi->audio_strm_length[n] / au_ssize); + } + } + } + } + if (avi->frames_hdr_all != 0) { + url_fseek(pb, avi->frames_hdr_all, SEEK_SET); + put_le32(pb, nb_frames); + } url_fseek(pb, file_size, SEEK_SET); } put_flush_packet(pb); diff --git a/libav/wav.c b/libav/wav.c index d367be7fe4..f909ddf738 100644 --- a/libav/wav.c +++ b/libav/wav.c @@ -33,7 +33,7 @@ CodecTag codec_wav_tags[] = { /* WAVEFORMATEX header */ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc) { - int tag, bps; + int tag, bps, blkalign, bytespersec; tag = codec_get_tag(codec_wav_tags, enc->codec_id); if (tag == 0) @@ -41,18 +41,39 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc) put_le16(pb, tag); put_le16(pb, enc->channels); put_le32(pb, enc->sample_rate); - put_le32(pb, enc->bit_rate / 8); - put_le16(pb, 1); /* block align */ if (enc->codec_id == CODEC_ID_PCM_U8 || enc->codec_id == CODEC_ID_PCM_ALAW || enc->codec_id == CODEC_ID_PCM_MULAW) { bps = 8; + } else if (enc->codec_id == CODEC_ID_MP2) { + bps = 0; } else { bps = 16; } - put_le16(pb, bps); /* bits per sample */ - put_le16(pb, 0); /* wav_extra_size */ + if (enc->codec_id == CODEC_ID_MP2) + blkalign = 1; + else + blkalign = enc->channels*bps >> 3; + if (enc->codec_id == CODEC_ID_PCM_U8 || + enc->codec_id == CODEC_ID_PCM_S16LE) { + bytespersec = enc->sample_rate * blkalign; + } else { + bytespersec = enc->bit_rate / 8; + } + put_le32(pb, bytespersec); /* bytes per second */ + put_le16(pb, blkalign); /* block align */ + put_le16(pb, bps); /* bits per sample */ + if (enc->codec_id == CODEC_ID_MP2) { + put_le16(pb, 12); /* wav_extra_size */ + put_le16(pb, 1); /* wID */ + put_le32(pb, 2); /* fdwFlags */ + put_le16(pb, 1152); /* nBlockSize */ + put_le16(pb, 1); /* nFramesPerBlock */ + put_le16(pb, 1393); /* nCodecDelay */ + } else + put_le16(pb, 0); /* wav_extra_size */ + return 0; }