} 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;
{ 0, 0 },
};
-CodecTag codec_wav_tags[] = {
- { CODEC_ID_MP2, 0x55 },
- { CODEC_ID_MP2, 0x50 },
- { CODEC_ID_AC3, 0x2000 },
- { CODEC_ID_PCM, 0x01 },
- { 0, 0 },
-};
-
-
unsigned int codec_get_tag(CodecTag *tags, int id)
{
while (tags->id != 0) {
put_le32(pb, 0);
}
-/* WAVEFORMATEX header */
-void put_wav_header(ByteIOContext *pb, AVCodecContext *enc)
+void parse_specific_params(AVCodecContext *stream, int *au_byterate, int *au_ssize, int *au_scale)
{
- int tag;
-
- tag = codec_get_tag(codec_wav_tags, enc->codec_id);
-
- 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 */
- put_le16(pb, 16); /* bits per sample */
- put_le16(pb, 0); /* wav_extra_size */
+ 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;
+ case CODEC_ID_MP3LAME:
+ *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;
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 */
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);
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;
put_bmp_header(pb, stream);
break;
case CODEC_TYPE_AUDIO:
- put_wav_header(pb, stream);
+ if (put_wav_header(pb, stream) < 0) {
+ free(avi);
+ return -1;
+ }
break;
}
end_tag(pb, strf);
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));
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)) {
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;n<s->nb_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 || stream->codec_id == CODEC_ID_MP3LAME) {
+ 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);