#define FRAGMENT_PIXELS 8
+static av_cold int vp3_decode_end(AVCodecContext *avctx);
+
typedef struct Coeff {
struct Coeff *next;
DCTELEM coeff;
int coded_fragment_list_index;
int pixel_addresses_initialized;
+ /* track which fragments have already been decoded; called 'fast'
+ * because this data structure avoids having to iterate through every
+ * fragment in coded_fragment_list; once a fragment has been fully
+ * decoded, it is removed from this list */
+ int *fast_fragment_list;
+ int fragment_list_y_head;
+ int fragment_list_c_head;
+
VLC dc_vlc[16];
VLC ac_vlc_1[16];
VLC ac_vlc_2[16];
/* end the list of coded C fragments */
s->last_coded_c_fragment = s->coded_fragment_list_index - 1;
+ for (i = 0; i < s->fragment_count - 1; i++) {
+ s->fast_fragment_list[i] = i + 1;
+ }
+ s->fast_fragment_list[s->fragment_count - 1] = -1;
+
+ if (s->last_coded_y_fragment == -1)
+ s->fragment_list_y_head = -1;
+ else {
+ s->fragment_list_y_head = s->first_coded_y_fragment;
+ s->fast_fragment_list[s->last_coded_y_fragment] = -1;
+ }
+
+ if (s->last_coded_c_fragment == -1)
+ s->fragment_list_c_head = -1;
+ else {
+ s->fragment_list_c_head = s->first_coded_c_fragment;
+ s->fast_fragment_list[s->last_coded_c_fragment] = -1;
+ }
+
return 0;
}
num_blocks_at_qpi += run_length;
for (j = 0; j < run_length; i++) {
- if (i > s->coded_fragment_list_index)
+ if (i >= s->coded_fragment_list_index)
return -1;
if (s->all_fragments[s->coded_fragment_list[i]].qpi == qpi) {
*/
static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
VLC *table, int coeff_index,
- int first_fragment, int last_fragment,
+ int y_plane,
int eob_run)
{
int i;
DCTELEM coeff = 0;
Vp3Fragment *fragment;
int bits_to_get;
+ int next_fragment;
+ int previous_fragment;
+ int fragment_num;
+ int *list_head;
/* local references to structure members to avoid repeated deferences */
uint8_t *perm= s->scantable.permutated;
Vp3Fragment *all_fragments = s->all_fragments;
uint8_t *coeff_counts = s->coeff_counts;
VLC_TYPE (*vlc_table)[2] = table->table;
+ int *fast_fragment_list = s->fast_fragment_list;
- if ((first_fragment >= s->fragment_count) ||
- (last_fragment >= s->fragment_count)) {
-
- av_log(s->avctx, AV_LOG_ERROR, " vp3:unpack_vlcs(): bad fragment number (%d -> %d ?)\n",
- first_fragment, last_fragment);
- return 0;
+ if (y_plane) {
+ next_fragment = s->fragment_list_y_head;
+ list_head = &s->fragment_list_y_head;
+ } else {
+ next_fragment = s->fragment_list_c_head;
+ list_head = &s->fragment_list_c_head;
}
- for (i = first_fragment; i <= last_fragment; i++) {
- int fragment_num = coded_fragment_list[i];
+ i = next_fragment;
+ previous_fragment = -1; /* this indicates that the previous fragment is actually the list head */
+ while (i != -1) {
+ fragment_num = coded_fragment_list[i];
- if (coeff_counts[fragment_num] > coeff_index)
+ if (coeff_counts[fragment_num] > coeff_index) {
+ previous_fragment = i;
+ i = fast_fragment_list[i];
continue;
+ }
fragment = &all_fragments[fragment_num];
if (!eob_run) {
s->next_coeff->next=NULL;
fragment->next_coeff= s->next_coeff++;
}
+ /* previous fragment is now this fragment */
+ previous_fragment = i;
} else {
coeff_counts[fragment_num] |= 128;
eob_run--;
+ /* remove this fragment from the list */
+ if (previous_fragment != -1)
+ fast_fragment_list[previous_fragment] = fast_fragment_list[i];
+ else
+ *list_head = fast_fragment_list[i];
+ /* previous fragment remains unchanged */
}
+
+ i = fast_fragment_list[i];
}
return eob_run;
int ac_y_table;
int ac_c_table;
int residual_eob_run = 0;
+ VLC *y_tables[64];
+ VLC *c_tables[64];
/* fetch the DC table indexes */
dc_y_table = get_bits(gb, 4);
/* unpack the Y plane DC coefficients */
residual_eob_run = unpack_vlcs(s, gb, &s->dc_vlc[dc_y_table], 0,
- s->first_coded_y_fragment, s->last_coded_y_fragment, residual_eob_run);
+ 1, residual_eob_run);
/* reverse prediction of the Y-plane DC coefficients */
reverse_dc_prediction(s, 0, s->fragment_width, s->fragment_height);
/* unpack the C plane DC coefficients */
residual_eob_run = unpack_vlcs(s, gb, &s->dc_vlc[dc_c_table], 0,
- s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run);
+ 0, residual_eob_run);
/* reverse prediction of the C-plane DC coefficients */
if (!(s->avctx->flags & CODEC_FLAG_GRAY))
ac_y_table = get_bits(gb, 4);
ac_c_table = get_bits(gb, 4);
- /* unpack the group 1 AC coefficients (coeffs 1-5) */
+ /* build tables of AC VLC tables */
for (i = 1; i <= 5; i++) {
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_1[ac_y_table], i,
- s->first_coded_y_fragment, s->last_coded_y_fragment, residual_eob_run);
-
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_1[ac_c_table], i,
- s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run);
+ y_tables[i] = &s->ac_vlc_1[ac_y_table];
+ c_tables[i] = &s->ac_vlc_1[ac_c_table];
}
-
- /* unpack the group 2 AC coefficients (coeffs 6-14) */
for (i = 6; i <= 14; i++) {
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_2[ac_y_table], i,
- s->first_coded_y_fragment, s->last_coded_y_fragment, residual_eob_run);
-
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_2[ac_c_table], i,
- s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run);
+ y_tables[i] = &s->ac_vlc_2[ac_y_table];
+ c_tables[i] = &s->ac_vlc_2[ac_c_table];
}
-
- /* unpack the group 3 AC coefficients (coeffs 15-27) */
for (i = 15; i <= 27; i++) {
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_3[ac_y_table], i,
- s->first_coded_y_fragment, s->last_coded_y_fragment, residual_eob_run);
-
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_3[ac_c_table], i,
- s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run);
+ y_tables[i] = &s->ac_vlc_3[ac_y_table];
+ c_tables[i] = &s->ac_vlc_3[ac_c_table];
}
-
- /* unpack the group 4 AC coefficients (coeffs 28-63) */
for (i = 28; i <= 63; i++) {
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_4[ac_y_table], i,
- s->first_coded_y_fragment, s->last_coded_y_fragment, residual_eob_run);
+ y_tables[i] = &s->ac_vlc_4[ac_y_table];
+ c_tables[i] = &s->ac_vlc_4[ac_c_table];
+ }
+
+ /* decode all AC coefficents */
+ for (i = 1; i <= 63; i++) {
+ if (s->fragment_list_y_head != -1)
+ residual_eob_run = unpack_vlcs(s, gb, y_tables[i], i,
+ 1, residual_eob_run);
- residual_eob_run = unpack_vlcs(s, gb, &s->ac_vlc_4[ac_c_table], i,
- s->first_coded_c_fragment, s->last_coded_c_fragment, residual_eob_run);
+ if (s->fragment_list_c_head != -1)
+ residual_eob_run = unpack_vlcs(s, gb, c_tables[i], i,
+ 0, residual_eob_run);
}
return 0;
*/
#define COMPATIBLE_FRAME(x) \
(compatible_frame[s->all_fragments[x].coding_method] == current_frame_type)
-#define FRAME_CODED(x) (s->all_fragments[x].coding_method != MODE_COPY)
#define DC_COEFF(u) (s->coeffs[u].index ? 0 : s->coeffs[u].coeff) //FIXME do somethin to simplify this
static void reverse_dc_prediction(Vp3DecodeContext *s,
* from other INTRA blocks. There are 2 golden frame coding types;
* blocks encoding in these modes can only predict from other blocks
* that were encoded with these 1 of these 2 modes. */
- static const unsigned char compatible_frame[8] = {
+ static const unsigned char compatible_frame[9] = {
1, /* MODE_INTER_NO_MV */
0, /* MODE_INTRA */
1, /* MODE_INTER_PLUS_MV */
1, /* MODE_INTER_PRIOR_MV */
2, /* MODE_USING_GOLDEN */
2, /* MODE_GOLDEN_MV */
- 1 /* MODE_INTER_FOUR_MV */
+ 1, /* MODE_INTER_FOUR_MV */
+ 3 /* MODE_COPY */
};
int current_frame_type;
if(x){
l= i-1;
vl = DC_COEFF(l);
- if(FRAME_CODED(l) && COMPATIBLE_FRAME(l))
+ if(COMPATIBLE_FRAME(l))
transform |= PL;
}
if(y){
u= i-fragment_width;
vu = DC_COEFF(u);
- if(FRAME_CODED(u) && COMPATIBLE_FRAME(u))
+ if(COMPATIBLE_FRAME(u))
transform |= PU;
if(x){
ul= i-fragment_width-1;
vul = DC_COEFF(ul);
- if(FRAME_CODED(ul) && COMPATIBLE_FRAME(ul))
+ if(COMPATIBLE_FRAME(ul))
transform |= PUL;
}
if(x + 1 < fragment_width){
ur= i-fragment_width+1;
vur = DC_COEFF(ur);
- if(FRAME_CODED(ur) && COMPATIBLE_FRAME(ur))
+ if(COMPATIBLE_FRAME(ur))
transform |= PUR;
}
}
/* check for outranging on the [ul u l] and
* [ul u ur l] predictors */
- if ((transform == 13) || (transform == 15)) {
+ if ((transform == 15) || (transform == 13)) {
if (FFABS(predicted_dc - vu) > 128)
predicted_dc = vu;
else if (FFABS(predicted_dc - vl) > 128)
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- /* do not perform left edge filter for left columns frags */
- if ((x > 0) &&
- (s->all_fragments[fragment].coding_method != MODE_COPY)) {
- s->dsp.vp3_h_loop_filter(
- plane_data + s->all_fragments[fragment].first_pixel,
- stride, bounding_values);
- }
+ /* This code basically just deblocks on the edges of coded blocks.
+ * However, it has to be much more complicated because of the
+ * braindamaged deblock ordering used in VP3/Theora. Order matters
+ * because some pixels get filtered twice. */
+ if( s->all_fragments[fragment].coding_method != MODE_COPY )
+ {
+ /* do not perform left edge filter for left columns frags */
+ if (x > 0) {
+ s->dsp.vp3_h_loop_filter(
+ plane_data + s->all_fragments[fragment].first_pixel,
+ stride, bounding_values);
+ }
- /* do not perform top edge filter for top row fragments */
- if ((y > 0) &&
- (s->all_fragments[fragment].coding_method != MODE_COPY)) {
- s->dsp.vp3_v_loop_filter(
- plane_data + s->all_fragments[fragment].first_pixel,
- stride, bounding_values);
- }
+ /* do not perform top edge filter for top row fragments */
+ if (y > 0) {
+ s->dsp.vp3_v_loop_filter(
+ plane_data + s->all_fragments[fragment].first_pixel,
+ stride, bounding_values);
+ }
- /* do not perform right edge filter for right column
- * fragments or if right fragment neighbor is also coded
- * in this frame (it will be filtered in next iteration) */
- if ((x < width - 1) &&
- (s->all_fragments[fragment].coding_method != MODE_COPY) &&
- (s->all_fragments[fragment + 1].coding_method == MODE_COPY)) {
- s->dsp.vp3_h_loop_filter(
- plane_data + s->all_fragments[fragment + 1].first_pixel,
- stride, bounding_values);
- }
+ /* do not perform right edge filter for right column
+ * fragments or if right fragment neighbor is also coded
+ * in this frame (it will be filtered in next iteration) */
+ if ((x < width - 1) &&
+ (s->all_fragments[fragment + 1].coding_method == MODE_COPY)) {
+ s->dsp.vp3_h_loop_filter(
+ plane_data + s->all_fragments[fragment + 1].first_pixel,
+ stride, bounding_values);
+ }
- /* do not perform bottom edge filter for bottom row
- * fragments or if bottom fragment neighbor is also coded
- * in this frame (it will be filtered in the next row) */
- if ((y < height - 1) &&
- (s->all_fragments[fragment].coding_method != MODE_COPY) &&
- (s->all_fragments[fragment + width].coding_method == MODE_COPY)) {
- s->dsp.vp3_v_loop_filter(
- plane_data + s->all_fragments[fragment + width].first_pixel,
- stride, bounding_values);
+ /* do not perform bottom edge filter for bottom row
+ * fragments or if bottom fragment neighbor is also coded
+ * in this frame (it will be filtered in the next row) */
+ if ((y < height - 1) &&
+ (s->all_fragments[fragment + width].coding_method == MODE_COPY)) {
+ s->dsp.vp3_v_loop_filter(
+ plane_data + s->all_fragments[fragment + width].first_pixel,
+ stride, bounding_values);
+ }
}
fragment++;
s->coeff_counts = av_malloc(s->fragment_count * sizeof(*s->coeff_counts));
s->coeffs = av_malloc(s->fragment_count * sizeof(Coeff) * 65);
s->coded_fragment_list = av_malloc(s->fragment_count * sizeof(int));
+ s->fast_fragment_list = av_malloc(s->fragment_count * sizeof(int));
s->pixel_addresses_initialized = 0;
+ if (!s->superblock_coding || !s->all_fragments || !s->coeff_counts ||
+ !s->coeffs || !s->coded_fragment_list || !s->fast_fragment_list) {
+ vp3_decode_end(avctx);
+ return -1;
+ }
if (!s->theora_tables)
{
s->superblock_macroblocks = av_malloc(s->superblock_count * 4 * sizeof(int));
s->macroblock_fragments = av_malloc(s->macroblock_count * 6 * sizeof(int));
s->macroblock_coding = av_malloc(s->macroblock_count + 1);
+ if (!s->superblock_fragments || !s->superblock_macroblocks ||
+ !s->macroblock_fragments || !s->macroblock_coding) {
+ vp3_decode_end(avctx);
+ return -1;
+ }
init_block_mapping(s);
for (i = 0; i < 3; i++) {
av_free(s->coeff_counts);
av_free(s->coeffs);
av_free(s->coded_fragment_list);
+ av_free(s->fast_fragment_list);
av_free(s->superblock_fragments);
av_free(s->superblock_macroblocks);
av_free(s->macroblock_fragments);