|
|
@@ -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;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) { |
|
|
|
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); |
|
|
|