History

lavc/dxvenc: improve compatibility with Resolume products

Improves compatibility with Resolume products by adding an additional hashtable for DXT color+LUT combinations, and padding the DXT texture dimensions to the next largest multiple of 16. Produces identical packets to Resolume Alley in manual tests.

Emma Worley committed 1 year ago

Commit d4556c91 parent 2de0d092 files · +86 −47Browse files

Showing the changes to libavcodec (1 of 2 files). Show all

Unified · Split

libavcodec/dxvenc.c+85−46
@@ -34,6 +34,11 @@ · 33 unmodified lines
3434
3535 #define DXV_HEADER_LENGTH 12
3636
37+/*
38+ * Resolume will refuse to display frames that are not padded to 16x16 pixels.
39+ */
40+#define DXV_ALIGN(x) FFALIGN(x, 16)
41+
3742 /*
3843 * DXV uses LZ-like back-references to avoid copying words that have already
3944 * appeared in the decompressed stream. Using a simple hash table (HT)
@@ -60,6 +65,7 @@ typedef struct DXVEncContext { · 20 unmodified lines
6065
6166 FFHashtableContext *color_ht;
6267 FFHashtableContext *lut_ht;
68+ FFHashtableContext *combo_ht;
6369 } DXVEncContext;
6470
6571 /* Converts an index offset value to a 2-bit opcode and pushes it to a stream.
@@ -94,10 +100,14 @@ static int dxv_compress_dxt1(AVCodecContext *avctx) · 28 unmodified lines
94100 DXVEncContext *ctx = avctx->priv_data;
95101 PutByteContext *pbc = &ctx->pbc;
96102 void *value;
97− uint32_t color, lut, idx, color_idx, lut_idx, prev_pos, state = 16, pos = 0, op = 0;
103+ uint64_t combo;
104+ uint32_t color, lut, idx, combo_idx, prev_pos, old_pos, state = 16, pos = 0, op = 0;
98105
99106 ff_hashtable_clear(ctx->color_ht);
100107 ff_hashtable_clear(ctx->lut_ht);
108+ ff_hashtable_clear(ctx->combo_ht);
109+
110+ ff_hashtable_set(ctx->combo_ht, ctx->tex_data, &pos);
101111
102112 bytestream2_put_le32(pbc, AV_RL32(ctx->tex_data));
103113 ff_hashtable_set(ctx->color_ht, ctx->tex_data, &pos);
@@ -107,51 +117,46 @@ static int dxv_compress_dxt1(AVCodecContext *avctx) · 3 unmodified lines
107117 pos++;
108118
109119 while (pos + 2 <= ctx->tex_size / 4) {
110− idx = 0;
111− color_idx = 0;
112− lut_idx = 0;
120+ combo = AV_RL64(ctx->tex_data + pos * 4);
121+ combo_idx = ff_hashtable_get(ctx->combo_ht, &combo, &prev_pos) ? pos - prev_pos : 0;
122+ idx = combo_idx;
123+ PUSH_OP(2);
124+ if (pos >= LOOKBACK_WORDS) {
125+ old_pos = pos - LOOKBACK_WORDS;
126+ if (ff_hashtable_get(ctx->combo_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos)
127+ ff_hashtable_delete(ctx->combo_ht, ctx->tex_data + old_pos * 4);
128+ }
129+ ff_hashtable_set(ctx->combo_ht, &combo, &pos);
113130
114131 color = AV_RL32(ctx->tex_data + pos * 4);
115− if (ff_hashtable_get(ctx->color_ht, &color, &prev_pos))
116− color_idx = pos - prev_pos;
117− ff_hashtable_set(ctx->color_ht, &color, &pos);
118−
132+ if (!combo_idx) {
133+ idx = ff_hashtable_get(ctx->color_ht, &color, &prev_pos) ? pos - prev_pos : 0;
134+ PUSH_OP(2);
135+ if (!idx)
136+ bytestream2_put_le32(pbc, color);
137+ }
119138 if (pos >= LOOKBACK_WORDS) {
120− uint32_t old_pos = pos - LOOKBACK_WORDS;
139+ old_pos = pos - LOOKBACK_WORDS;
121140 if (ff_hashtable_get(ctx->color_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos)
122141 ff_hashtable_delete(ctx->color_ht, ctx->tex_data + old_pos * 4);
123142 }
143+ ff_hashtable_set(ctx->color_ht, &color, &pos);
124144 pos++;
125145
126146 lut = AV_RL32(ctx->tex_data + pos * 4);
127− if (color_idx && lut == AV_RL32(ctx->tex_data + (pos - color_idx) * 4)) {
128− idx = color_idx;
129− } else {
130− idx = 0;
131− if (ff_hashtable_get(ctx->lut_ht, &lut, &prev_pos))
132− lut_idx = pos - prev_pos;
133− ff_hashtable_set(ctx->lut_ht, &lut, &pos);
147+ if (!combo_idx) {
148+ idx = ff_hashtable_get(ctx->lut_ht, &lut, &prev_pos) ? pos - prev_pos : 0;
149+ PUSH_OP(2);
150+ if (!idx)
151+ bytestream2_put_le32(pbc, lut);
134152 }
135153 if (pos >= LOOKBACK_WORDS) {
136− uint32_t old_pos = pos - LOOKBACK_WORDS;
154+ old_pos = pos - LOOKBACK_WORDS;
137155 if (ff_hashtable_get(ctx->lut_ht, ctx->tex_data + old_pos * 4, &prev_pos) && prev_pos <= old_pos)
138156 ff_hashtable_delete(ctx->lut_ht, ctx->tex_data + old_pos * 4);
139157 }
158+ ff_hashtable_set(ctx->lut_ht, &lut, &pos);
140159 pos++;
141−
142− PUSH_OP(2);
143−
144− if (!idx) {
145− idx = color_idx;
146− PUSH_OP(2);
147− if (!idx)
148− bytestream2_put_le32(pbc, color);
149−
150− idx = lut_idx;
151− PUSH_OP(2);
152− if (!idx)
153− bytestream2_put_le32(pbc, lut);
154− }
155160 }
156161
157162 return 0;
@@ -172,12 +177,50 @@ static int dxv_encode(AVCodecContext *avctx, AVPacket *pkt, · 14 unmodified lines
172177 return ret;
173178
174179 if (ctx->enc.tex_funct) {
180+ uint8_t *safe_data[4] = {frame->data[0], 0, 0, 0};
181+ int safe_linesize[4] = {frame->linesize[0], 0, 0, 0};
182+
183+ if (avctx->width != DXV_ALIGN(avctx->width) || avctx->height != DXV_ALIGN(avctx->height)) {
184+ ret = av_image_alloc(
185+ safe_data,
186+ safe_linesize,
187+ DXV_ALIGN(avctx->width),
188+ DXV_ALIGN(avctx->height),
189+ avctx->pix_fmt,
190+ 1);
191+ if (ret < 0)
192+ return ret;
193+
194+ av_image_copy2(
195+ safe_data,
196+ safe_linesize,
197+ frame->data,
198+ frame->linesize,
199+ avctx->pix_fmt,
200+ avctx->width,
201+ avctx->height);
202+
203+ if (avctx->width != DXV_ALIGN(avctx->width)) {
204+ for (int y = 0; y < avctx->height; y++) {
205+ memset(safe_data[0] + y * safe_linesize[0] + frame->linesize[0], 0, safe_linesize[0] - frame->linesize[0]);
206+ }
207+ }
208+ if (avctx->height != DXV_ALIGN(avctx->height)) {
209+ for (int y = avctx->height; y < DXV_ALIGN(avctx->height); y++) {
210+ memset(safe_data[0] + y * safe_linesize[0], 0, safe_linesize[0]);
211+ }
212+ }
213+ }
214+
175215 ctx->enc.tex_data.out = ctx->tex_data;
176− ctx->enc.frame_data.in = frame->data[0];
177− ctx->enc.stride = frame->linesize[0];
178− ctx->enc.width = avctx->width;
179− ctx->enc.height = avctx->height;
216+ ctx->enc.frame_data.in = safe_data[0];
217+ ctx->enc.stride = safe_linesize[0];
218+ ctx->enc.width = DXV_ALIGN(avctx->width);
219+ ctx->enc.height = DXV_ALIGN(avctx->height);
180220 ff_texturedsp_exec_compress_threads(avctx, &ctx->enc);
221+
222+ if (safe_data[0] != frame->data[0])
223+ av_freep(&safe_data[0]);
181224 } else {
182225 /* unimplemented: YCoCg formats */
183226 return AVERROR_INVALIDDATA;
@@ -216,14 +259,6 @@ static av_cold int dxv_init(AVCodecContext *avctx) · 32 unmodified lines
216259 return ret;
217260 }
218261
219− if (avctx->width % TEXTURE_BLOCK_W || avctx->height % TEXTURE_BLOCK_H) {
220− av_log(avctx,
221− AV_LOG_ERROR,
222− "Video size %dx%d is not multiple of "AV_STRINGIFY(TEXTURE_BLOCK_W)"x"AV_STRINGIFY(TEXTURE_BLOCK_H)".\n",
223− avctx->width, avctx->height);
224− return AVERROR_INVALIDDATA;
225− }
226−
227262 ff_texturedspenc_init(&texdsp);
228263
229264 switch (ctx->tex_fmt) {
@@ -237,10 +272,10 @@ static av_cold int dxv_init(AVCodecContext *avctx) · 7 unmodified lines
237272 return AVERROR_INVALIDDATA;
238273 }
239274 ctx->enc.raw_ratio = 16;
240− ctx->tex_size = avctx->width / TEXTURE_BLOCK_W *
241− avctx->height / TEXTURE_BLOCK_H *
275+ ctx->tex_size = DXV_ALIGN(avctx->width) / TEXTURE_BLOCK_W *
276+ DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H *
242277 ctx->enc.tex_ratio;
243− ctx->enc.slice_count = av_clip(avctx->thread_count, 1, avctx->height / TEXTURE_BLOCK_H);
278+ ctx->enc.slice_count = av_clip(avctx->thread_count, 1, DXV_ALIGN(avctx->height) / TEXTURE_BLOCK_H);
244279
245280 ctx->tex_data = av_malloc(ctx->tex_size);
246281 if (!ctx->tex_data) {
@@ -251,6 +286,9 @@ static av_cold int dxv_init(AVCodecContext *avctx) · 4 unmodified lines
251286 if (ret < 0)
252287 return ret;
253288 ret = ff_hashtable_alloc(&ctx->lut_ht, sizeof(uint32_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS);
289+ if (ret < 0)
290+ return ret;
291+ ret = ff_hashtable_alloc(&ctx->combo_ht, sizeof(uint64_t), sizeof(uint32_t), LOOKBACK_HT_ELEMS);
254292 if (ret < 0)
255293 return ret;
256294
@@ -265,6 +303,7 @@ static av_cold int dxv_close(AVCodecContext *avctx) · 8 unmodified lines
265303
266304 ff_hashtable_freep(&ctx->color_ht);
267305 ff_hashtable_freep(&ctx->lut_ht);
306+ ff_hashtable_freep(&ctx->combo_ht);
268307
269308 return 0;
270309 }

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