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
38 AVCodecContext *avctx;38 AVCodecContext *avctx;
39 39
40 GetByteContext gb;40 GetByteContext gb;
41 ThreadFrame previous_picture;
41 ThreadFrame last_picture;42 ThreadFrame last_picture;
42 ThreadFrame picture;43 ThreadFrame picture;
43 44
@@ -55,6 +56,7 @@ typedef struct PNGDecContext { · 11 unmodified lines
55 int bits_per_pixel;56 int bits_per_pixel;
56 int bpp;57 int bpp;
57 58
59 int frame_id;
58 uint8_t *image_buf;60 uint8_t *image_buf;
59 int image_linesize;61 int image_linesize;
60 uint32_t palette[256];62 uint32_t palette[256];
@@ -827,13 +829,14 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s, · 766 unmodified lines
827 return AVERROR_INVALIDDATA;829 return AVERROR_INVALIDDATA;
828 830
829 /* always (re)start with a clean frame */831 /* always (re)start with a clean frame */
830 if (sequence_number == 0)832 if (sequence_number == 0) {
831 s->dispose_op = APNG_DISPOSE_OP_BACKGROUND;833 s->dispose_op = APNG_DISPOSE_OP_BACKGROUND;
832 834 s->frame_id = 0;
833 if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {835 } else {
834 av_log(avctx, AV_LOG_ERROR,836 s->frame_id++;
835 "Dispose operation 'previous' is not yet implemented, using 'none'.\n");837 if (s->frame_id == 1 && s->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
836 s->dispose_op = APNG_DISPOSE_OP_NONE;838 /* previous for the second frame is the first frame */
839 s->dispose_op = APNG_DISPOSE_OP_NONE;
837 }840 }
838 841
839 return 0;842 return 0;
@@ -864,8 +867,9 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 24 unmodified lines
864{867{
865 int i, j;868 int i, j;
866 uint8_t *pd = p->data[0];869 uint8_t *pd = p->data[0];
867 /* TODO make pd_last point to the one before for APNG_DISPOSE_OP_PREVIOUS */
868 uint8_t *pd_last = s->last_picture.f->data[0];870 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];
869 int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp);873 int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp);
870 874
871 if (s->blend_op == APNG_BLEND_OP_OVER &&875 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
876 }880 }
877 881
878 ff_thread_await_progress(&s->last_picture, INT_MAX, 0);882 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
879 for (j = 0; j < s->y_offset; j++) {886 for (j = 0; j < s->y_offset; j++) {
880 for (i = 0; i < ls; i++)887 for (i = 0; i < ls; i++)
881 pd[i] = pd_last[i];888 pd[i] = pd_last[i];
@@ -886,6 +893,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 4 unmodified lines
886 if (s->dispose_op != APNG_DISPOSE_OP_BACKGROUND && s->blend_op == APNG_BLEND_OP_OVER) {893 if (s->dispose_op != APNG_DISPOSE_OP_BACKGROUND && s->blend_op == APNG_BLEND_OP_OVER) {
887 uint8_t ri, gi, bi, ai;894 uint8_t ri, gi, bi, ai;
888 895
896 pd_last_region += s->y_offset * s->image_linesize;
889 if (avctx->pix_fmt == AV_PIX_FMT_RGBA) {897 if (avctx->pix_fmt == AV_PIX_FMT_RGBA) {
890 ri = 0;898 ri = 0;
891 gi = 1;899 gi = 1;
@@ -907,17 +915,17 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 15 unmodified lines
907 /* output = alpha * foreground + (1-alpha) * background */915 /* output = alpha * foreground + (1-alpha) * background */
908 switch (alpha) {916 switch (alpha) {
909 case 0:917 case 0:
910 pd[i+ri] = pd_last[i+ri];918 pd[i+ri] = pd_last_region[i+ri];
911 pd[i+gi] = pd_last[i+gi];919 pd[i+gi] = pd_last_region[i+gi];
912 pd[i+bi] = pd_last[i+bi];920 pd[i+bi] = pd_last_region[i+bi];
913 pd[i+ai] = 0xff;921 pd[i+ai] = 0xff;
914 break;922 break;
915 case 255:923 case 255:
916 break;924 break;
917 default:925 default:
918 pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last[i+ri]);926 pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last_region[i+ri]);
919 pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last[i+gi]);927 pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last_region[i+gi]);
920 pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last[i+bi]);928 pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last_region[i+bi]);
921 pd[i+ai] = 0xff;929 pd[i+ai] = 0xff;
922 break;930 break;
923 }931 }
@@ -926,6 +934,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, · 2 unmodified lines
926 pd[i] = pd_last[i];934 pd[i] = pd_last[i];
927 pd += s->image_linesize;935 pd += s->image_linesize;
928 pd_last += s->image_linesize;936 pd_last += s->image_linesize;
937 pd_last_region += s->image_linesize;
929 }938 }
930 } else {939 } else {
931 for (j = s->y_offset; j < s->y_offset + s->cur_h; j++) {940 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
955 uint32_t tag, length;964 uint32_t tag, length;
956 int decode_next_dat = 0;965 int decode_next_dat = 0;
957 int ret = AVERROR_INVALIDDATA;966 int ret = AVERROR_INVALIDDATA;
967 AVFrame *ref;
958 968
959 for (;;) {969 for (;;) {
960 length = bytestream2_get_bytes_left(&s->gb);970 length = bytestream2_get_bytes_left(&s->gb);
@@ -1053,11 +1063,13 @@ exit_loop: · 92 unmodified lines
1053 handle_small_bpp(s, p);1063 handle_small_bpp(s, p);
1054 1064
1055 /* handle p-frames only if a predecessor frame is available */1065 /* 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]) {
1057 if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")1069 if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
1058 && s->last_picture.f->width == p->width1070 && ref->width == p->width
1059 && s->last_picture.f->height== p->height1071 && ref->height== p->height
1060 && s->last_picture.f->format== p->format1072 && ref->format== p->format
1061 ) {1073 ) {
1062 if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)1074 if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)
1063 handle_p_frame_png(s, p);1075 handle_p_frame_png(s, p);
@@ -1141,9 +1153,13 @@ static int decode_frame_apng(AVCodecContext *avctx, · 77 unmodified lines
1141 PNGDecContext *const s = avctx->priv_data;1153 PNGDecContext *const s = avctx->priv_data;
1142 int ret;1154 int ret;
1143 AVFrame *p;1155 AVFrame *p;
1156 ThreadFrame tmp;
1144 1157
1145 ff_thread_release_buffer(avctx, &s->last_picture);1158 ff_thread_release_buffer(avctx, &s->previous_picture);
1146 FFSWAP(ThreadFrame, s->picture, s->last_picture);1159 tmp = s->previous_picture;
1160 s->previous_picture = s->last_picture;
1161 s->last_picture = s->picture;
1162 s->picture = tmp;
1147 p = s->picture.f;1163 p = s->picture.f;
1148 1164
1149 if (!(s->state & PNG_IHDR)) {1165 if (!(s->state & PNG_IHDR)) {
@@ -1193,13 +1209,22 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) · 43 unmodified lines
1193{1209{
1194 PNGDecContext *psrc = src->priv_data;1210 PNGDecContext *psrc = src->priv_data;
1195 PNGDecContext *pdst = dst->priv_data;1211 PNGDecContext *pdst = dst->priv_data;
1212 int ret;
1196 1213
1197 if (dst == src)1214 if (dst == src)
1198 return 0;1215 return 0;
1199 1216
1217 pdst->frame_id = psrc->frame_id;
1218
1200 ff_thread_release_buffer(dst, &pdst->picture);1219 ff_thread_release_buffer(dst, &pdst->picture);
1201 if (psrc->picture.f->data[0])1220 if (psrc->picture.f->data[0] &&
1202 return ff_thread_ref_frame(&pdst->picture, &psrc->picture);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 }
1203 1228
1204 return 0;1229 return 0;
1205}1230}
@@ -1209,9 +1234,10 @@ static av_cold int png_dec_init(AVCodecContext *avctx) · 3 unmodified lines
1209 PNGDecContext *s = avctx->priv_data;1234 PNGDecContext *s = avctx->priv_data;
1210 1235
1211 s->avctx = avctx;1236 s->avctx = avctx;
1237 s->previous_picture.f = av_frame_alloc();
1212 s->last_picture.f = av_frame_alloc();1238 s->last_picture.f = av_frame_alloc();
1213 s->picture.f = av_frame_alloc();1239 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)
1215 return AVERROR(ENOMEM);1241 return AVERROR(ENOMEM);
1216 1242
1217 if (!avctx->internal->is_copy) {1243 if (!avctx->internal->is_copy) {
@@ -1226,6 +1252,8 @@ static av_cold int png_dec_end(AVCodecContext *avctx) · 8 unmodified lines
1226{1252{
1227 PNGDecContext *s = avctx->priv_data;1253 PNGDecContext *s = avctx->priv_data;
1228 1254
1255 ff_thread_release_buffer(avctx, &s->previous_picture);
1256 av_frame_free(&s->previous_picture.f);
1229 ff_thread_release_buffer(avctx, &s->last_picture);1257 ff_thread_release_buffer(avctx, &s->last_picture);
1230 av_frame_free(&s->last_picture.f);1258 av_frame_free(&s->last_picture.f);
1231 ff_thread_release_buffer(avctx, &s->picture);1259 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