*/
typedef struct AVIIentry {
- unsigned int flags, pos, len;
+ char tag[4];
+ unsigned int flags;
+ unsigned int pos;
+ unsigned int len;
} AVIIentry;
#define AVI_INDEX_CLUSTER_SIZE 16384
int64_t last_dts;
AVIIndex indexes;
+
+ int64_t strh_flags_offset;
+
+ uint32_t palette[AVPALETTE_COUNT];
+ uint32_t old_palette[AVPALETTE_COUNT];
+ int64_t pal_offset;
} AVIStream;
-static int avi_write_packet(AVFormatContext *s, AVPacket *pkt);
+static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt);
static inline AVIIentry *avi_get_ientry(const AVIIndex *idx, int ent_id)
{
return &idx->cluster[cl][id];
}
+static int avi_add_ientry(AVFormatContext *s, int stream_index, char *tag,
+ unsigned int flags, unsigned int size)
+{
+ AVIContext *avi = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVIIndex *idx = &avist->indexes;
+ int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
+ int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
+
+ if (idx->ents_allocated <= idx->entry) {
+ idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
+ if (!idx->cluster) {
+ idx->ents_allocated = 0;
+ idx->entry = 0;
+ return AVERROR(ENOMEM);
+ }
+ idx->cluster[cl] =
+ av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry));
+ if (!idx->cluster[cl])
+ return AVERROR(ENOMEM);
+ idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
+ }
+
+ if (tag)
+ memcpy(idx->cluster[cl][id].tag, tag, 4);
+ else
+ memset(idx->cluster[cl][id].tag, 0, 4);
+ idx->cluster[cl][id].flags = flags;
+ idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
+ idx->cluster[cl][id].len = size;
+ avist->max_size = FFMAX(avist->max_size, size);
+ idx->entry++;
+
+ return 0;
+}
+
static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb,
const char *riff_tag, const char *list_tag)
{
avio_wl32(pb, enc->codec_tag);
else
avio_wl32(pb, 1);
+ avist->strh_flags_offset = avio_tell(pb);
avio_wl32(pb, 0); /* flags */
avio_wl16(pb, 0); /* priority */
avio_wl16(pb, 0); /* language */
&& enc->pix_fmt == AV_PIX_FMT_RGB555LE
&& enc->bits_per_coded_sample == 15)
enc->bits_per_coded_sample = 16;
+ avist->pal_offset = avio_tell(pb) + 40;
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 (!empty) {
avist = s->streams[stream_id]->priv_data;
- avi_stream2fourcc(tag, stream_id,
+ if (*ie->tag)
+ ffio_wfourcc(pb, ie->tag);
+ else {
+ avi_stream2fourcc(tag, stream_id,
s->streams[stream_id]->codec->codec_type);
- ffio_wfourcc(pb, tag);
+ ffio_wfourcc(pb, tag);
+ }
avio_wl32(pb, ie->flags);
avio_wl32(pb, ie->pos);
avio_wl32(pb, ie->len);
empty_packet.size = 0;
empty_packet.data = NULL;
empty_packet.stream_index = stream_index;
- avi_write_packet(s, &empty_packet);
+ avi_write_packet_internal(s, &empty_packet);
ff_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count);
}
static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
{
- unsigned char tag[5];
- unsigned int flags = 0;
const int stream_index = pkt->stream_index;
- int size = pkt->size;
- AVIContext *avi = s->priv_data;
- AVIOContext *pb = s->pb;
- AVIStream *avist = s->streams[stream_index]->priv_data;
AVCodecContext *enc = s->streams[stream_index]->codec;
int ret;
if ((ret = write_skip_frames(s, stream_index, pkt->dts)) < 0)
return ret;
+ if (!pkt->size)
+ return avi_write_packet_internal(s, pkt); /* Passthrough */
+
+ if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVIOContext *pb = s->pb;
+ AVPacket *opkt = pkt;
+ if (enc->codec_id == AV_CODEC_ID_RAWVIDEO && enc->codec_tag == 0) {
+ int64_t bpc = enc->bits_per_coded_sample != 15 ? enc->bits_per_coded_sample : 16;
+ int expected_stride = ((enc->width * bpc + 31) >> 5)*4;
+ ret = ff_reshuffle_raw_rgb(s, &pkt, enc, expected_stride);
+ if (ret < 0)
+ return ret;
+ } else
+ ret = 0;
+ if (enc->pix_fmt == AV_PIX_FMT_PAL8) {
+ int ret2 = ff_get_packet_palette(s, opkt, ret, avist->palette);
+ if (ret2 < 0)
+ return ret2;
+ if (ret2) {
+ int pal_size = 1 << enc->bits_per_coded_sample;
+ int pc_tag, i;
+
+ av_assert0(enc->bits_per_coded_sample >= 0 && enc->bits_per_coded_sample <= 8);
+
+ if (pb->seekable && avist->pal_offset) {
+ int64_t cur_offset = avio_tell(pb);
+ avio_seek(pb, avist->pal_offset, SEEK_SET);
+ for (i = 0; i < pal_size; i++) {
+ uint32_t v = avist->palette[i];
+ avio_wl32(pb, v & 0xffffff);
+ }
+ avio_seek(pb, cur_offset, SEEK_SET);
+ memcpy(avist->old_palette, avist->palette, pal_size * 4);
+ avist->pal_offset = 0;
+ }
+ if (memcmp(avist->palette, avist->old_palette, pal_size * 4)) {
+ unsigned char tag[5];
+ avi_stream2fourcc(tag, stream_index, enc->codec_type);
+ tag[2] = 'p'; tag[3] = 'c';
+ if (s->pb->seekable) {
+ int ret;
+ if (avist->strh_flags_offset) {
+ int64_t cur_offset = avio_tell(pb);
+ avio_seek(pb, avist->strh_flags_offset, SEEK_SET);
+ avio_wl32(pb, AVISF_VIDEO_PALCHANGES);
+ avio_seek(pb, cur_offset, SEEK_SET);
+ avist->strh_flags_offset = 0;
+ }
+ ret = avi_add_ientry(s, stream_index, tag, AVIIF_NO_TIME,
+ pal_size * 4 + 4);
+ if (ret < 0)
+ return ret;
+ }
+ pc_tag = ff_start_tag(pb, tag);
+ avio_w8(pb, 0);
+ avio_w8(pb, pal_size & 0xFF);
+ avio_wl16(pb, 0); // reserved
+ for (i = 0; i < pal_size; i++) {
+ uint32_t v = avist->palette[i];
+ avio_wb32(pb, v<<8);
+ }
+ ff_end_tag(pb, pc_tag);
+ memcpy(avist->old_palette, avist->palette, pal_size * 4);
+ }
+ }
+ }
+ if (ret) {
+ ret = avi_write_packet_internal(s, pkt);
+ av_packet_free(&pkt);
+ return ret;
+ }
+ }
+
+ return avi_write_packet_internal(s, pkt);
+}
+
+static int avi_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+{
+ unsigned char tag[5];
+ unsigned int flags = 0;
+ const int stream_index = pkt->stream_index;
+ int size = pkt->size;
+ AVIContext *avi = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVCodecContext *enc = s->streams[stream_index]->codec;
+
if (pkt->dts != AV_NOPTS_VALUE)
avist->last_dts = pkt->dts + pkt->duration;
avist->audio_strm_length += size;
if (s->pb->seekable) {
- AVIIndex *idx = &avist->indexes;
- int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
- int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
- if (idx->ents_allocated <= idx->entry) {
- idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
- if (!idx->cluster) {
- idx->ents_allocated = 0;
- idx->entry = 0;
- return AVERROR(ENOMEM);
- }
- idx->cluster[cl] =
- av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry));
- if (!idx->cluster[cl])
- return AVERROR(ENOMEM);
- idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
- }
-
- idx->cluster[cl][id].flags = flags;
- idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
- idx->cluster[cl][id].len = size;
- avist->max_size = FFMAX(avist->max_size, size);
- idx->entry++;
+ int ret;
+ ret = avi_add_ientry(s, stream_index, NULL, flags, size);
+ if (ret < 0)
+ return ret;
}
avio_write(pb, tag, 4);