*/
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
int max_size;
int sample_requested;
- int64_t pal_offset;
- int hdr_pal_done;
-
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_internal(AVFormatContext *s, AVPacket *pkt);
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 */
}
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);
static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
{
- unsigned char tag[5];
const int stream_index = pkt->stream_index;
- const uint8_t *data = pkt->data;
- int size = pkt->size;
- AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[stream_index]->codec;
- AVIStream *avist = s->streams[stream_index]->priv_data;
int ret;
if (enc->codec_id == AV_CODEC_ID_H264 && enc->codec_tag == MKTAG('H','2','6','4') && pkt->size) {
if ((ret = write_skip_frames(s, stream_index, pkt->dts)) < 0)
return ret;
- 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;
- if (ret) {
- if (ret == CONTAINS_PAL) {
- int pc_tag, i;
+ 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;
- if (!avist->hdr_pal_done) {
+ 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 = AV_RL32(data + size - 4*pal_size + 4*i);
+ uint32_t v = avist->palette[i];
avio_wl32(pb, v & 0xffffff);
}
avio_seek(pb, cur_offset, SEEK_SET);
- avist->hdr_pal_done++;
+ memcpy(avist->old_palette, avist->palette, pal_size * 4);
+ avist->pal_offset = 0;
}
- avi_stream2fourcc(tag, stream_index, enc->codec_type);
- tag[2] = 'p'; tag[3] = 'c';
- 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 = AV_RL32(data + size - 4*pal_size + 4*i);
- avio_wb32(pb, v<<8);
+ 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);
}
- ff_end_tag(pb, pc_tag);
}
+ }
+ if (ret) {
ret = avi_write_packet_internal(s, pkt);
av_packet_free(&pkt);
return ret;
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);