+/// Release and shuffle frames after decode finishes
+static void update_frames(AVCodecContext *avctx)
+{
+ Vp3DecodeContext *s = avctx->priv_data;
+
+ /* release the last frame, if it is allocated and if it is not the
+ * golden frame */
+ if (s->last_frame.data[0] && s->last_frame.type != FF_BUFFER_TYPE_COPY)
+ ff_thread_release_buffer(avctx, &s->last_frame);
+
+ /* shuffle frames (last = current) */
+ s->last_frame= s->current_frame;
+
+ if (s->keyframe) {
+ if (s->golden_frame.data[0])
+ ff_thread_release_buffer(avctx, &s->golden_frame);
+ s->golden_frame = s->current_frame;
+ s->last_frame.type = FF_BUFFER_TYPE_COPY;
+ }
+
+ s->current_frame.data[0]= NULL; /* ensure that we catch any access to this released frame */
+}
+
+static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+ Vp3DecodeContext *s = dst->priv_data, *s1 = src->priv_data;
+ int qps_changed = 0, i, err;
+
+ if (!s1->current_frame.data[0]
+ ||s->width != s1->width
+ ||s->height!= s1->height)
+ return -1;
+
+ if (s != s1) {
+ // init tables if the first frame hasn't been decoded
+ if (!s->current_frame.data[0]) {
+ int y_fragment_count, c_fragment_count;
+ s->avctx = dst;
+ err = allocate_tables(dst);
+ if (err)
+ return err;
+ y_fragment_count = s->fragment_width[0] * s->fragment_height[0];
+ c_fragment_count = s->fragment_width[1] * s->fragment_height[1];
+ memcpy(s->motion_val[0], s1->motion_val[0], y_fragment_count * sizeof(*s->motion_val[0]));
+ memcpy(s->motion_val[1], s1->motion_val[1], c_fragment_count * sizeof(*s->motion_val[1]));
+ }
+
+#define copy_fields(to, from, start_field, end_field) memcpy(&to->start_field, &from->start_field, (char*)&to->end_field - (char*)&to->start_field)
+
+ // copy previous frame data
+ copy_fields(s, s1, golden_frame, dsp);
+
+ // copy qscale data if necessary
+ for (i = 0; i < 3; i++) {
+ if (s->qps[i] != s1->qps[1]) {
+ qps_changed = 1;
+ memcpy(&s->qmat[i], &s1->qmat[i], sizeof(s->qmat[i]));
+ }
+ }
+
+ if (s->qps[0] != s1->qps[0])
+ memcpy(&s->bounding_values_array, &s1->bounding_values_array, sizeof(s->bounding_values_array));
+
+ if (qps_changed)
+ copy_fields(s, s1, qps, superblock_count);
+#undef copy_fields
+ }
+
+ update_frames(dst);
+
+ return 0;
+}
+