History

libavcodec/pngdec: support 'previous' dispose operation for APNG.

Benoit Fouet committed 11 years ago

Commit 08aec6f1 parent 49d9cbe1 file · +50 −22Browse files

Unified · Split

libavcodec/pngdec.c+50−22
@@ -38,6 +38,7 @@ typedef struct PNGDecContext { · 37 unmodified lines
3838 AVCodecContext *avctx;
3939
4040 GetByteContext gb;
41+ ThreadFrame previous_picture;
4142 ThreadFrame last_picture;
4243 ThreadFrame picture;
4344
@@ -55,6 +56,7 @@ typedef struct PNGDecContext { · 11 unmodified lines
5556 int bits_per_pixel;
5657 int bpp;
5758
59+ int frame_id;
5860 uint8_t *image_buf;
5961 int image_linesize;
6062 uint32_t palette[256];
@@ -827,13 +829,14 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s, · 766 unmodified lines
827829 return AVERROR_INVALIDDATA;
828830
829831 /* always (re)start with a clean frame */
830− if (sequence_number == 0)
832+ if (sequence_number == 0) {
831833 s->dispose_op = APNG_DISPOSE_OP_BACKGROUND;
832−
833− if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
834− av_log(avctx, AV_LOG_ERROR,
835− "Dispose operation 'previous' is not yet implemented, using 'none'.\n");
836− s->dispose_op = APNG_DISPOSE_OP_NONE;
834+ s->frame_id = 0;
835+ } else {
836+ s->frame_id++;
837+ if (s->frame_id == 1 && s->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
838+ /* previous for the second frame is the first frame */
839+ s->dispose_op = APNG_DISPOSE_OP_NONE;
837840 }
838841
839842 return 0;
@@ -864,8 +867,9 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 24 unmodified lines
864867 {
865868 int i, j;
866869 uint8_t *pd = p->data[0];
867− /* TODO make pd_last point to the one before for APNG_DISPOSE_OP_PREVIOUS */
868870 uint8_t *pd_last = s->last_picture.f->data[0];
871+ uint8_t *pd_last_region = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
872+ s->previous_picture.f->data[0] : s->last_picture.f->data[0];
869873 int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp);
870874
871875 if (s->blend_op == APNG_BLEND_OP_OVER &&
@@ -876,6 +880,9 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 4 unmodified lines
876880 }
877881
878882 ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
883+ if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
884+ ff_thread_await_progress(&s->previous_picture, INT_MAX, 0);
885+
879886 for (j = 0; j < s->y_offset; j++) {
880887 for (i = 0; i < ls; i++)
881888 pd[i] = pd_last[i];
@@ -886,6 +893,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 4 unmodified lines
886893 if (s->dispose_op != APNG_DISPOSE_OP_BACKGROUND && s->blend_op == APNG_BLEND_OP_OVER) {
887894 uint8_t ri, gi, bi, ai;
888895
896+ pd_last_region += s->y_offset * s->image_linesize;
889897 if (avctx->pix_fmt == AV_PIX_FMT_RGBA) {
890898 ri = 0;
891899 gi = 1;
@@ -907,17 +915,17 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 15 unmodified lines
907915 /* output = alpha * foreground + (1-alpha) * background */
908916 switch (alpha) {
909917 case 0:
910− pd[i+ri] = pd_last[i+ri];
911− pd[i+gi] = pd_last[i+gi];
912− pd[i+bi] = pd_last[i+bi];
918+ pd[i+ri] = pd_last_region[i+ri];
919+ pd[i+gi] = pd_last_region[i+gi];
920+ pd[i+bi] = pd_last_region[i+bi];
913921 pd[i+ai] = 0xff;
914922 break;
915923 case 255:
916924 break;
917925 default:
918− pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last[i+ri]);
919− pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last[i+gi]);
920− pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last[i+bi]);
926+ pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last_region[i+ri]);
927+ pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last_region[i+gi]);
928+ pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last_region[i+bi]);
921929 pd[i+ai] = 0xff;
922930 break;
923931 }
@@ -926,6 +934,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 2 unmodified lines
926934 pd[i] = pd_last[i];
927935 pd += s->image_linesize;
928936 pd_last += s->image_linesize;
937+ pd_last_region += s->image_linesize;
929938 }
930939 } else {
931940 for (j = s->y_offset; j < s->y_offset + s->cur_h; j++) {
@@ -955,6 +964,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, · 23 unmodified lines
955964 uint32_t tag, length;
956965 int decode_next_dat = 0;
957966 int ret = AVERROR_INVALIDDATA;
967+ AVFrame *ref;
958968
959969 for (;;) {
960970 length = bytestream2_get_bytes_left(&s->gb);
@@ -1053,11 +1063,13 @@ exit_loop: · 92 unmodified lines
10531063 handle_small_bpp(s, p);
10541064
10551065 /* handle p-frames only if a predecessor frame is available */
1056− if (s->last_picture.f->data[0]) {
1066+ ref = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
1067+ s->previous_picture.f : s->last_picture.f;
1068+ if (ref->data[0]) {
10571069 if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
1058− && s->last_picture.f->width == p->width
1059− && s->last_picture.f->height== p->height
1060− && s->last_picture.f->format== p->format
1070+ && ref->width == p->width
1071+ && ref->height== p->height
1072+ && ref->format== p->format
10611073 ) {
10621074 if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)
10631075 handle_p_frame_png(s, p);
@@ -1141,9 +1153,13 @@ static int decode_frame_apng(AVCodecContext *avctx, · 77 unmodified lines
11411153 PNGDecContext *const s = avctx->priv_data;
11421154 int ret;
11431155 AVFrame *p;
1156+ ThreadFrame tmp;
11441157
1145− ff_thread_release_buffer(avctx, &s->last_picture);
1146− FFSWAP(ThreadFrame, s->picture, s->last_picture);
1158+ ff_thread_release_buffer(avctx, &s->previous_picture);
1159+ tmp = s->previous_picture;
1160+ s->previous_picture = s->last_picture;
1161+ s->last_picture = s->picture;
1162+ s->picture = tmp;
11471163 p = s->picture.f;
11481164
11491165 if (!(s->state & PNG_IHDR)) {
@@ -1193,13 +1209,22 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) · 43 unmodified lines
11931209 {
11941210 PNGDecContext *psrc = src->priv_data;
11951211 PNGDecContext *pdst = dst->priv_data;
1212+ int ret;
11961213
11971214 if (dst == src)
11981215 return 0;
11991216
1217+ pdst->frame_id = psrc->frame_id;
1218+
12001219 ff_thread_release_buffer(dst, &pdst->picture);
1201− if (psrc->picture.f->data[0])
1202− return ff_thread_ref_frame(&pdst->picture, &psrc->picture);
1220+ if (psrc->picture.f->data[0] &&
1221+ (ret = ff_thread_ref_frame(&pdst->picture, &psrc->picture)) < 0)
1222+ return ret;
1223+ if (CONFIG_APNG_DECODER && dst->codec_id == AV_CODEC_ID_APNG) {
1224+ ff_thread_release_buffer(dst, &pdst->last_picture);
1225+ if (psrc->last_picture.f->data[0])
1226+ return ff_thread_ref_frame(&pdst->last_picture, &psrc->last_picture);
1227+ }
12031228
12041229 return 0;
12051230 }
@@ -1209,9 +1234,10 @@ static av_cold int png_dec_init(AVCodecContext *avctx) · 3 unmodified lines
12091234 PNGDecContext *s = avctx->priv_data;
12101235
12111236 s->avctx = avctx;
1237+ s->previous_picture.f = av_frame_alloc();
12121238 s->last_picture.f = av_frame_alloc();
12131239 s->picture.f = av_frame_alloc();
1214− if (!s->last_picture.f || !s->picture.f)
1240+ if (!s->previous_picture.f || !s->last_picture.f || !s->picture.f)
12151241 return AVERROR(ENOMEM);
12161242
12171243 if (!avctx->internal->is_copy) {
@@ -1226,6 +1252,8 @@ static av_cold int png_dec_end(AVCodecContext *avctx) · 8 unmodified lines
12261252 {
12271253 PNGDecContext *s = avctx->priv_data;
12281254
1255+ ff_thread_release_buffer(avctx, &s->previous_picture);
1256+ av_frame_free(&s->previous_picture.f);
12291257 ff_thread_release_buffer(avctx, &s->last_picture);
12301258 av_frame_free(&s->last_picture.f);
12311259 ff_thread_release_buffer(avctx, &s->picture);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t