2 * Error resilience / concealment
4 * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * @file error_resilience.c
25 * Error resilience / concealment.
32 #include "mpegvideo.h"
34 static void decode_mb(MpegEncContext
*s
){
35 s
->dest
[0] = s
->current_picture
.data
[0] + (s
->mb_y
* 16* s
->linesize
) + s
->mb_x
* 16;
36 s
->dest
[1] = s
->current_picture
.data
[1] + (s
->mb_y
* 8 * s
->uvlinesize
) + s
->mb_x
* 8;
37 s
->dest
[2] = s
->current_picture
.data
[2] + (s
->mb_y
* 8 * s
->uvlinesize
) + s
->mb_x
* 8;
39 MPV_decode_mb(s
, s
->block
);
43 * replaces the current MB with a flat dc only version.
45 static void put_dc(MpegEncContext
*s
, uint8_t *dest_y
, uint8_t *dest_cb
, uint8_t *dest_cr
, int mb_x
, int mb_y
)
47 int dc
, dcu
, dcv
, y
, i
;
49 dc
= s
->dc_val
[0][mb_x
*2 + (i
&1) + (mb_y
*2 + (i
>>1))*s
->b8_stride
];
51 else if(dc
>2040) dc
=2040;
55 dest_y
[x
+ (i
&1)*8 + (y
+ (i
>>1)*8)*s
->linesize
]= dc
/8;
59 dcu
= s
->dc_val
[1][mb_x
+ mb_y
*s
->mb_stride
];
60 dcv
= s
->dc_val
[2][mb_x
+ mb_y
*s
->mb_stride
];
62 else if(dcu
>2040) dcu
=2040;
64 else if(dcv
>2040) dcv
=2040;
68 dest_cb
[x
+ y
*(s
->uvlinesize
)]= dcu
/8;
69 dest_cr
[x
+ y
*(s
->uvlinesize
)]= dcv
/8;
74 static void filter181(int16_t *data
, int width
, int height
, int stride
){
77 /* horizontal filter */
78 for(y
=1; y
<height
-1; y
++){
79 int prev_dc
= data
[0 + y
*stride
];
81 for(x
=1; x
<width
-1; x
++){
85 + data
[x
+ y
*stride
]*8
86 - data
[x
+ 1 + y
*stride
];
87 dc
= (dc
*10923 + 32768)>>16;
88 prev_dc
= data
[x
+ y
*stride
];
89 data
[x
+ y
*stride
]= dc
;
94 for(x
=1; x
<width
-1; x
++){
97 for(y
=1; y
<height
-1; y
++){
101 + data
[x
+ y
*stride
]*8
102 - data
[x
+ (y
+1)*stride
];
103 dc
= (dc
*10923 + 32768)>>16;
104 prev_dc
= data
[x
+ y
*stride
];
105 data
[x
+ y
*stride
]= dc
;
111 * guess the dc of blocks which do not have an undamaged dc
112 * @param w width in 8 pixel blocks
113 * @param h height in 8 pixel blocks
115 static void guess_dc(MpegEncContext
*s
, int16_t *dc
, int w
, int h
, int stride
, int is_luma
){
118 for(b_y
=0; b_y
<h
; b_y
++){
119 for(b_x
=0; b_x
<w
; b_x
++){
120 int color
[4]={1024,1024,1024,1024};
121 int distance
[4]={9999,9999,9999,9999};
122 int mb_index
, error
, j
;
123 int64_t guess
, weight_sum
;
125 mb_index
= (b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
127 error
= s
->error_status_table
[mb_index
];
129 if(IS_INTER(s
->current_picture
.mb_type
[mb_index
])) continue; //inter
130 if(!(error
&DC_ERROR
)) continue; //dc-ok
133 for(j
=b_x
+1; j
<w
; j
++){
134 int mb_index_j
= (j
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
135 int error_j
= s
->error_status_table
[mb_index_j
];
136 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
137 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
138 color
[0]= dc
[j
+ b_y
*stride
];
145 for(j
=b_x
-1; j
>=0; j
--){
146 int mb_index_j
= (j
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
147 int error_j
= s
->error_status_table
[mb_index_j
];
148 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
149 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
150 color
[1]= dc
[j
+ b_y
*stride
];
157 for(j
=b_y
+1; j
<h
; j
++){
158 int mb_index_j
= (b_x
>>is_luma
) + (j
>>is_luma
)*s
->mb_stride
;
159 int error_j
= s
->error_status_table
[mb_index_j
];
160 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
161 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
162 color
[2]= dc
[b_x
+ j
*stride
];
169 for(j
=b_y
-1; j
>=0; j
--){
170 int mb_index_j
= (b_x
>>is_luma
) + (j
>>is_luma
)*s
->mb_stride
;
171 int error_j
= s
->error_status_table
[mb_index_j
];
172 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
173 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
174 color
[3]= dc
[b_x
+ j
*stride
];
183 int64_t weight
= 256*256*256*16/distance
[j
];
184 guess
+= weight
*(int64_t)color
[j
];
187 guess
= (guess
+ weight_sum
/2) / weight_sum
;
189 dc
[b_x
+ b_y
*stride
]= guess
;
195 * simple horizontal deblocking filter used for error resilience
196 * @param w width in 8 pixel blocks
197 * @param h height in 8 pixel blocks
199 static void h_block_filter(MpegEncContext
*s
, uint8_t *dst
, int w
, int h
, int stride
, int is_luma
){
201 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
203 for(b_y
=0; b_y
<h
; b_y
++){
204 for(b_x
=0; b_x
<w
-1; b_x
++){
206 int left_status
= s
->error_status_table
[( b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
];
207 int right_status
= s
->error_status_table
[((b_x
+1)>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
];
208 int left_intra
= IS_INTRA(s
->current_picture
.mb_type
[( b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
]);
209 int right_intra
= IS_INTRA(s
->current_picture
.mb_type
[((b_x
+1)>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
]);
210 int left_damage
= left_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
211 int right_damage
= right_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
212 int offset
= b_x
*8 + b_y
*stride
*8;
213 int16_t *left_mv
= s
->current_picture
.motion_val
[0][s
->b8_stride
*(b_y
<<(1-is_luma
)) + ( b_x
<<(1-is_luma
))];
214 int16_t *right_mv
= s
->current_picture
.motion_val
[0][s
->b8_stride
*(b_y
<<(1-is_luma
)) + ((b_x
+1)<<(1-is_luma
))];
216 if(!(left_damage
||right_damage
)) continue; // both undamaged
218 if( (!left_intra
) && (!right_intra
)
219 && FFABS(left_mv
[0]-right_mv
[0]) + FFABS(left_mv
[1]+right_mv
[1]) < 2) continue;
224 a
= dst
[offset
+ 7 + y
*stride
] - dst
[offset
+ 6 + y
*stride
];
225 b
= dst
[offset
+ 8 + y
*stride
] - dst
[offset
+ 7 + y
*stride
];
226 c
= dst
[offset
+ 9 + y
*stride
] - dst
[offset
+ 8 + y
*stride
];
228 d
= FFABS(b
) - ((FFABS(a
) + FFABS(c
) + 1)>>1);
234 if(!(left_damage
&& right_damage
))
238 dst
[offset
+ 7 + y
*stride
] = cm
[dst
[offset
+ 7 + y
*stride
] + ((d
*7)>>4)];
239 dst
[offset
+ 6 + y
*stride
] = cm
[dst
[offset
+ 6 + y
*stride
] + ((d
*5)>>4)];
240 dst
[offset
+ 5 + y
*stride
] = cm
[dst
[offset
+ 5 + y
*stride
] + ((d
*3)>>4)];
241 dst
[offset
+ 4 + y
*stride
] = cm
[dst
[offset
+ 4 + y
*stride
] + ((d
*1)>>4)];
244 dst
[offset
+ 8 + y
*stride
] = cm
[dst
[offset
+ 8 + y
*stride
] - ((d
*7)>>4)];
245 dst
[offset
+ 9 + y
*stride
] = cm
[dst
[offset
+ 9 + y
*stride
] - ((d
*5)>>4)];
246 dst
[offset
+ 10+ y
*stride
] = cm
[dst
[offset
+10 + y
*stride
] - ((d
*3)>>4)];
247 dst
[offset
+ 11+ y
*stride
] = cm
[dst
[offset
+11 + y
*stride
] - ((d
*1)>>4)];
255 * simple vertical deblocking filter used for error resilience
256 * @param w width in 8 pixel blocks
257 * @param h height in 8 pixel blocks
259 static void v_block_filter(MpegEncContext
*s
, uint8_t *dst
, int w
, int h
, int stride
, int is_luma
){
261 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
263 for(b_y
=0; b_y
<h
-1; b_y
++){
264 for(b_x
=0; b_x
<w
; b_x
++){
266 int top_status
= s
->error_status_table
[(b_x
>>is_luma
) + ( b_y
>>is_luma
)*s
->mb_stride
];
267 int bottom_status
= s
->error_status_table
[(b_x
>>is_luma
) + ((b_y
+1)>>is_luma
)*s
->mb_stride
];
268 int top_intra
= IS_INTRA(s
->current_picture
.mb_type
[(b_x
>>is_luma
) + ( b_y
>>is_luma
)*s
->mb_stride
]);
269 int bottom_intra
= IS_INTRA(s
->current_picture
.mb_type
[(b_x
>>is_luma
) + ((b_y
+1)>>is_luma
)*s
->mb_stride
]);
270 int top_damage
= top_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
271 int bottom_damage
= bottom_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
272 int offset
= b_x
*8 + b_y
*stride
*8;
273 int16_t *top_mv
= s
->current_picture
.motion_val
[0][s
->b8_stride
*( b_y
<<(1-is_luma
)) + (b_x
<<(1-is_luma
))];
274 int16_t *bottom_mv
= s
->current_picture
.motion_val
[0][s
->b8_stride
*((b_y
+1)<<(1-is_luma
)) + (b_x
<<(1-is_luma
))];
276 if(!(top_damage
||bottom_damage
)) continue; // both undamaged
278 if( (!top_intra
) && (!bottom_intra
)
279 && FFABS(top_mv
[0]-bottom_mv
[0]) + FFABS(top_mv
[1]+bottom_mv
[1]) < 2) continue;
284 a
= dst
[offset
+ x
+ 7*stride
] - dst
[offset
+ x
+ 6*stride
];
285 b
= dst
[offset
+ x
+ 8*stride
] - dst
[offset
+ x
+ 7*stride
];
286 c
= dst
[offset
+ x
+ 9*stride
] - dst
[offset
+ x
+ 8*stride
];
288 d
= FFABS(b
) - ((FFABS(a
) + FFABS(c
)+1)>>1);
294 if(!(top_damage
&& bottom_damage
))
298 dst
[offset
+ x
+ 7*stride
] = cm
[dst
[offset
+ x
+ 7*stride
] + ((d
*7)>>4)];
299 dst
[offset
+ x
+ 6*stride
] = cm
[dst
[offset
+ x
+ 6*stride
] + ((d
*5)>>4)];
300 dst
[offset
+ x
+ 5*stride
] = cm
[dst
[offset
+ x
+ 5*stride
] + ((d
*3)>>4)];
301 dst
[offset
+ x
+ 4*stride
] = cm
[dst
[offset
+ x
+ 4*stride
] + ((d
*1)>>4)];
304 dst
[offset
+ x
+ 8*stride
] = cm
[dst
[offset
+ x
+ 8*stride
] - ((d
*7)>>4)];
305 dst
[offset
+ x
+ 9*stride
] = cm
[dst
[offset
+ x
+ 9*stride
] - ((d
*5)>>4)];
306 dst
[offset
+ x
+ 10*stride
] = cm
[dst
[offset
+ x
+ 10*stride
] - ((d
*3)>>4)];
307 dst
[offset
+ x
+ 11*stride
] = cm
[dst
[offset
+ x
+ 11*stride
] - ((d
*1)>>4)];
314 static void guess_mv(MpegEncContext
*s
){
315 uint8_t fixed
[s
->mb_stride
* s
->mb_height
];
318 #define MV_UNCHANGED 1
319 const int mb_stride
= s
->mb_stride
;
320 const int mb_width
= s
->mb_width
;
321 const int mb_height
= s
->mb_height
;
322 int i
, depth
, num_avail
;
326 for(i
=0; i
<s
->mb_num
; i
++){
327 const int mb_xy
= s
->mb_index2xy
[ i
];
329 int error
= s
->error_status_table
[mb_xy
];
331 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
])) f
=MV_FROZEN
; //intra //FIXME check
332 if(!(error
&MV_ERROR
)) f
=MV_FROZEN
; //inter with undamaged MV
339 if((!(s
->avctx
->error_concealment
&FF_EC_GUESS_MVS
)) || num_avail
<= mb_width
/2){
340 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
341 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
342 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
344 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
])) continue;
345 if(!(s
->error_status_table
[mb_xy
]&MV_ERROR
)) continue;
347 s
->mv_dir
= MV_DIR_FORWARD
;
349 s
->mv_type
= MV_TYPE_16X16
;
352 s
->dsp
.clear_blocks(s
->block
[0]);
364 for(depth
=0;; depth
++){
365 int changed
, pass
, none_left
;
369 for(pass
=0; (changed
|| pass
<2) && pass
<10; pass
++){
374 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
375 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
376 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
377 int mv_predictor
[8][2]={{0}};
380 int best_score
=256*256*256*64;
382 const int mot_stride
= s
->b8_stride
;
383 const int mot_index
= mb_x
*2 + mb_y
*2*mot_stride
;
384 int prev_x
= s
->current_picture
.motion_val
[0][mot_index
][0];
385 int prev_y
= s
->current_picture
.motion_val
[0][mot_index
][1];
387 if((mb_x
^mb_y
^pass
)&1) continue;
389 if(fixed
[mb_xy
]==MV_FROZEN
) continue;
390 assert(!IS_INTRA(s
->current_picture
.mb_type
[mb_xy
]));
391 assert(s
->last_picture_ptr
&& s
->last_picture_ptr
->data
[0]);
394 if(mb_x
>0 && fixed
[mb_xy
-1 ]==MV_FROZEN
) j
=1;
395 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1 ]==MV_FROZEN
) j
=1;
396 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]==MV_FROZEN
) j
=1;
397 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]==MV_FROZEN
) j
=1;
401 if(mb_x
>0 && fixed
[mb_xy
-1 ]==MV_CHANGED
) j
=1;
402 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1 ]==MV_CHANGED
) j
=1;
403 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]==MV_CHANGED
) j
=1;
404 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]==MV_CHANGED
) j
=1;
405 if(j
==0 && pass
>1) continue;
409 if(mb_x
>0 && fixed
[mb_xy
-1]){
410 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
- 2][0];
411 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
- 2][1];
414 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1]){
415 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
+ 2][0];
416 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
+ 2][1];
419 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]){
420 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
- mot_stride
*2][0];
421 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
- mot_stride
*2][1];
424 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]){
425 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
+ mot_stride
*2][0];
426 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
+ mot_stride
*2][1];
429 if(pred_count
==0) continue;
432 int sum_x
=0, sum_y
=0;
433 int max_x
, max_y
, min_x
, min_y
;
435 for(j
=0; j
<pred_count
; j
++){
436 sum_x
+= mv_predictor
[j
][0];
437 sum_y
+= mv_predictor
[j
][1];
441 mv_predictor
[pred_count
][0] = sum_x
/j
;
442 mv_predictor
[pred_count
][1] = sum_y
/j
;
449 min_x
=min_y
=max_x
=max_y
=0;
451 for(j
=0; j
<pred_count
; j
++){
452 max_x
= FFMAX(max_x
, mv_predictor
[j
][0]);
453 max_y
= FFMAX(max_y
, mv_predictor
[j
][1]);
454 min_x
= FFMIN(min_x
, mv_predictor
[j
][0]);
455 min_y
= FFMIN(min_y
, mv_predictor
[j
][1]);
457 mv_predictor
[pred_count
+1][0] = sum_x
- max_x
- min_x
;
458 mv_predictor
[pred_count
+1][1] = sum_y
- max_y
- min_y
;
461 mv_predictor
[pred_count
+1][0] /= 2;
462 mv_predictor
[pred_count
+1][1] /= 2;
471 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
][0];
472 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
][1];
475 s
->mv_dir
= MV_DIR_FORWARD
;
477 s
->mv_type
= MV_TYPE_16X16
;
480 s
->dsp
.clear_blocks(s
->block
[0]);
485 for(j
=0; j
<pred_count
; j
++){
487 uint8_t *src
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
489 s
->current_picture
.motion_val
[0][mot_index
][0]= s
->mv
[0][0][0]= mv_predictor
[j
][0];
490 s
->current_picture
.motion_val
[0][mot_index
][1]= s
->mv
[0][0][1]= mv_predictor
[j
][1];
494 if(mb_x
>0 && fixed
[mb_xy
-1]){
497 score
+= FFABS(src
[k
*s
->linesize
-1 ]-src
[k
*s
->linesize
]);
499 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1]){
502 score
+= FFABS(src
[k
*s
->linesize
+15]-src
[k
*s
->linesize
+16]);
504 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]){
507 score
+= FFABS(src
[k
-s
->linesize
]-src
[k
]);
509 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]){
512 score
+= FFABS(src
[k
+s
->linesize
*15]-src
[k
+s
->linesize
*16]);
515 if(score
<= best_score
){ // <= will favor the last MV
520 score_sum
+= best_score
;
521 //FIXME no need to set s->current_picture.motion_val[0][mot_index][0] explicit
522 s
->current_picture
.motion_val
[0][mot_index
][0]= s
->mv
[0][0][0]= mv_predictor
[best_pred
][0];
523 s
->current_picture
.motion_val
[0][mot_index
][1]= s
->mv
[0][0][1]= mv_predictor
[best_pred
][1];
528 if(s
->mv
[0][0][0] != prev_x
|| s
->mv
[0][0][1] != prev_y
){
529 fixed
[mb_xy
]=MV_CHANGED
;
532 fixed
[mb_xy
]=MV_UNCHANGED
;
536 // printf(".%d/%d", changed, score_sum); fflush(stdout);
542 for(i
=0; i
<s
->mb_num
; i
++){
543 int mb_xy
= s
->mb_index2xy
[i
];
545 fixed
[mb_xy
]=MV_FROZEN
;
547 // printf(":"); fflush(stdout);
551 static int is_intra_more_likely(MpegEncContext
*s
){
552 int is_intra_likely
, i
, j
, undamaged_count
, skip_amount
, mb_x
, mb_y
;
554 if(s
->last_picture_ptr
==NULL
) return 1; //no previous frame available -> use spatial prediction
557 for(i
=0; i
<s
->mb_num
; i
++){
558 const int mb_xy
= s
->mb_index2xy
[i
];
559 const int error
= s
->error_status_table
[mb_xy
];
560 if(!((error
&DC_ERROR
) && (error
&MV_ERROR
)))
564 if(undamaged_count
< 5) return 0; //almost all MBs damaged -> use temporal prediction
567 //prevent dsp.sad() check, that requires access to the image
568 if(s
->avctx
->xvmc_acceleration
&& s
->pict_type
==FF_I_TYPE
) return 1;
571 skip_amount
= FFMAX(undamaged_count
/50, 1); //check only upto 50 MBs
575 for(mb_y
= 0; mb_y
<s
->mb_height
-1; mb_y
++){
576 for(mb_x
= 0; mb_x
<s
->mb_width
; mb_x
++){
578 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
580 error
= s
->error_status_table
[mb_xy
];
581 if((error
&DC_ERROR
) && (error
&MV_ERROR
))
582 continue; //skip damaged
585 if((j
%skip_amount
) != 0) continue; //skip a few to speed things up
587 if(s
->pict_type
==FF_I_TYPE
){
588 uint8_t *mb_ptr
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
589 uint8_t *last_mb_ptr
= s
->last_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
591 is_intra_likely
+= s
->dsp
.sad
[0](NULL
, last_mb_ptr
, mb_ptr
, s
->linesize
, 16);
592 is_intra_likely
-= s
->dsp
.sad
[0](NULL
, last_mb_ptr
, last_mb_ptr
+s
->linesize
*16, s
->linesize
, 16);
594 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
]))
601 //printf("is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
602 return is_intra_likely
> 0;
605 void ff_er_frame_start(MpegEncContext
*s
){
606 if(!s
->error_resilience
) return;
608 memset(s
->error_status_table
, MV_ERROR
|AC_ERROR
|DC_ERROR
|VP_START
|AC_END
|DC_END
|MV_END
, s
->mb_stride
*s
->mb_height
*sizeof(uint8_t));
609 s
->error_count
= 3*s
->mb_num
;
614 * @param endx x component of the last macroblock, can be -1 for the last of the previous line
615 * @param status the status at the end (MV_END, AC_ERROR, ...), it is assumed that no earlier end or
616 * error of the same type occurred
618 void ff_er_add_slice(MpegEncContext
*s
, int startx
, int starty
, int endx
, int endy
, int status
){
619 const int start_i
= av_clip(startx
+ starty
* s
->mb_width
, 0, s
->mb_num
-1);
620 const int end_i
= av_clip(endx
+ endy
* s
->mb_width
, 0, s
->mb_num
);
621 const int start_xy
= s
->mb_index2xy
[start_i
];
622 const int end_xy
= s
->mb_index2xy
[end_i
];
625 if(start_i
> end_i
|| start_xy
> end_xy
){
626 av_log(s
->avctx
, AV_LOG_ERROR
, "internal error, slice end before start\n");
630 if(!s
->error_resilience
) return;
633 if(status
& (AC_ERROR
|AC_END
)){
634 mask
&= ~(AC_ERROR
|AC_END
);
635 s
->error_count
-= end_i
- start_i
+ 1;
637 if(status
& (DC_ERROR
|DC_END
)){
638 mask
&= ~(DC_ERROR
|DC_END
);
639 s
->error_count
-= end_i
- start_i
+ 1;
641 if(status
& (MV_ERROR
|MV_END
)){
642 mask
&= ~(MV_ERROR
|MV_END
);
643 s
->error_count
-= end_i
- start_i
+ 1;
646 if(status
& (AC_ERROR
|DC_ERROR
|MV_ERROR
)) s
->error_count
= INT_MAX
;
649 memset(&s
->error_status_table
[start_xy
], 0, (end_xy
- start_xy
) * sizeof(uint8_t));
652 for(i
=start_xy
; i
<end_xy
; i
++){
653 s
->error_status_table
[ i
] &= mask
;
657 if(end_i
== s
->mb_num
)
658 s
->error_count
= INT_MAX
;
660 s
->error_status_table
[end_xy
] &= mask
;
661 s
->error_status_table
[end_xy
] |= status
;
664 s
->error_status_table
[start_xy
] |= VP_START
;
666 if(start_xy
> 0 && s
->avctx
->thread_count
<= 1 && s
->avctx
->skip_top
*s
->mb_width
< start_i
){
667 int prev_status
= s
->error_status_table
[ s
->mb_index2xy
[start_i
- 1] ];
669 prev_status
&= ~ VP_START
;
670 if(prev_status
!= (MV_END
|DC_END
|AC_END
)) s
->error_count
= INT_MAX
;
674 void ff_er_frame_end(MpegEncContext
*s
){
675 int i
, mb_x
, mb_y
, error
, error_type
, dc_error
, mv_error
, ac_error
;
677 int threshold_part
[4]= {100,100,100};
680 int size
= s
->b8_stride
* 2 * s
->mb_height
;
681 Picture
*pic
= s
->current_picture_ptr
;
683 if(!s
->error_resilience
|| s
->error_count
==0 ||
684 s
->error_count
==3*s
->mb_width
*(s
->avctx
->skip_top
+ s
->avctx
->skip_bottom
)) return;
686 if(s
->current_picture
.motion_val
[0] == NULL
){
687 av_log(s
->avctx
, AV_LOG_ERROR
, "Warning MVs not available\n");
690 pic
->ref_index
[i
]= av_mallocz(size
* sizeof(uint8_t));
691 pic
->motion_val_base
[i
]= av_mallocz((size
+4) * 2 * sizeof(uint16_t));
692 pic
->motion_val
[i
]= pic
->motion_val_base
[i
]+4;
694 pic
->motion_subsample_log2
= 3;
695 s
->current_picture
= *s
->current_picture_ptr
;
699 if(pic
->ref_index
[i
])
700 memset(pic
->ref_index
[i
], 0, size
* sizeof(uint8_t));
703 if(s
->avctx
->debug
&FF_DEBUG_ER
){
704 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
705 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
706 int status
= s
->error_status_table
[mb_x
+ mb_y
*s
->mb_stride
];
708 av_log(s
->avctx
, AV_LOG_DEBUG
, "%2X ", status
);
710 av_log(s
->avctx
, AV_LOG_DEBUG
, "\n");
715 /* handle overlapping slices */
716 for(error_type
=1; error_type
<=3; error_type
++){
719 for(i
=s
->mb_num
-1; i
>=0; i
--){
720 const int mb_xy
= s
->mb_index2xy
[i
];
721 int error
= s
->error_status_table
[mb_xy
];
723 if(error
&(1<<error_type
))
725 if(error
&(8<<error_type
))
729 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
737 /* handle slices with partitions of different length */
738 if(s
->partitioned_frame
){
741 for(i
=s
->mb_num
-1; i
>=0; i
--){
742 const int mb_xy
= s
->mb_index2xy
[i
];
743 int error
= s
->error_status_table
[mb_xy
];
747 if((error
&MV_END
) || (error
&DC_END
) || (error
&AC_ERROR
))
751 s
->error_status_table
[mb_xy
]|= AC_ERROR
;
758 /* handle missing slices */
759 if(s
->error_resilience
>=4){
762 for(i
=s
->mb_num
-2; i
>=s
->mb_width
+100; i
--){ //FIXME +100 hack
763 const int mb_xy
= s
->mb_index2xy
[i
];
764 int error1
= s
->error_status_table
[mb_xy
];
765 int error2
= s
->error_status_table
[s
->mb_index2xy
[i
+1]];
770 if( error2
==(VP_START
|DC_ERROR
|AC_ERROR
|MV_ERROR
|AC_END
|DC_END
|MV_END
)
771 && error1
!=(VP_START
|DC_ERROR
|AC_ERROR
|MV_ERROR
|AC_END
|DC_END
|MV_END
)
772 && ((error1
&AC_END
) || (error1
&DC_END
) || (error1
&MV_END
))){ //end & uninit
777 s
->error_status_table
[mb_xy
]|= DC_ERROR
|AC_ERROR
|MV_ERROR
;
782 /* backward mark errors */
784 for(error_type
=1; error_type
<=3; error_type
++){
785 for(i
=s
->mb_num
-1; i
>=0; i
--){
786 const int mb_xy
= s
->mb_index2xy
[i
];
787 int error
= s
->error_status_table
[mb_xy
];
789 if(!s
->mbskip_table
[mb_xy
]) //FIXME partition specific
791 if(error
&(1<<error_type
))
794 if(s
->partitioned_frame
){
795 if(distance
< threshold_part
[error_type
-1])
796 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
798 if(distance
< threshold
)
799 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
808 /* forward mark errors */
810 for(i
=0; i
<s
->mb_num
; i
++){
811 const int mb_xy
= s
->mb_index2xy
[i
];
812 int old_error
= s
->error_status_table
[mb_xy
];
814 if(old_error
&VP_START
)
815 error
= old_error
& (DC_ERROR
|AC_ERROR
|MV_ERROR
);
817 error
|= old_error
& (DC_ERROR
|AC_ERROR
|MV_ERROR
);
818 s
->error_status_table
[mb_xy
]|= error
;
822 /* handle not partitioned case */
823 if(!s
->partitioned_frame
){
824 for(i
=0; i
<s
->mb_num
; i
++){
825 const int mb_xy
= s
->mb_index2xy
[i
];
826 error
= s
->error_status_table
[mb_xy
];
827 if(error
&(AC_ERROR
|DC_ERROR
|MV_ERROR
))
828 error
|= AC_ERROR
|DC_ERROR
|MV_ERROR
;
829 s
->error_status_table
[mb_xy
]= error
;
834 dc_error
= ac_error
= mv_error
=0;
835 for(i
=0; i
<s
->mb_num
; i
++){
836 const int mb_xy
= s
->mb_index2xy
[i
];
837 error
= s
->error_status_table
[mb_xy
];
838 if(error
&DC_ERROR
) dc_error
++;
839 if(error
&AC_ERROR
) ac_error
++;
840 if(error
&MV_ERROR
) mv_error
++;
842 av_log(s
->avctx
, AV_LOG_INFO
, "concealing %d DC, %d AC, %d MV errors\n", dc_error
, ac_error
, mv_error
);
844 is_intra_likely
= is_intra_more_likely(s
);
846 /* set unknown mb-type to most likely */
847 for(i
=0; i
<s
->mb_num
; i
++){
848 const int mb_xy
= s
->mb_index2xy
[i
];
849 error
= s
->error_status_table
[mb_xy
];
850 if(!((error
&DC_ERROR
) && (error
&MV_ERROR
)))
854 s
->current_picture
.mb_type
[mb_xy
]= MB_TYPE_INTRA4x4
;
856 s
->current_picture
.mb_type
[mb_xy
]= MB_TYPE_16x16
| MB_TYPE_L0
;
859 /* handle inter blocks with damaged AC */
860 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
861 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
862 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
863 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
864 error
= s
->error_status_table
[mb_xy
];
866 if(IS_INTRA(mb_type
)) continue; //intra
867 if(error
&MV_ERROR
) continue; //inter with damaged MV
868 if(!(error
&AC_ERROR
)) continue; //undamaged inter
870 s
->mv_dir
= MV_DIR_FORWARD
;
874 int mb_index
= mb_x
*2 + mb_y
*2*s
->b8_stride
;
876 s
->mv_type
= MV_TYPE_8X8
;
878 s
->mv
[0][j
][0] = s
->current_picture
.motion_val
[0][ mb_index
+ (j
&1) + (j
>>1)*s
->b8_stride
][0];
879 s
->mv
[0][j
][1] = s
->current_picture
.motion_val
[0][ mb_index
+ (j
&1) + (j
>>1)*s
->b8_stride
][1];
882 s
->mv_type
= MV_TYPE_16X16
;
883 s
->mv
[0][0][0] = s
->current_picture
.motion_val
[0][ mb_x
*2 + mb_y
*2*s
->b8_stride
][0];
884 s
->mv
[0][0][1] = s
->current_picture
.motion_val
[0][ mb_x
*2 + mb_y
*2*s
->b8_stride
][1];
887 s
->dsp
.clear_blocks(s
->block
[0]);
896 if(s
->pict_type
==FF_B_TYPE
){
897 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
898 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
899 int xy
= mb_x
*2 + mb_y
*2*s
->b8_stride
;
900 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
901 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
902 error
= s
->error_status_table
[mb_xy
];
904 if(IS_INTRA(mb_type
)) continue;
905 if(!(error
&MV_ERROR
)) continue; //inter with undamaged MV
906 if(!(error
&AC_ERROR
)) continue; //undamaged inter
908 s
->mv_dir
= MV_DIR_FORWARD
|MV_DIR_BACKWARD
;
910 s
->mv_type
= MV_TYPE_16X16
;
914 int time_pp
= s
->pp_time
;
915 int time_pb
= s
->pb_time
;
917 s
->mv
[0][0][0] = s
->next_picture
.motion_val
[0][xy
][0]*time_pb
/time_pp
;
918 s
->mv
[0][0][1] = s
->next_picture
.motion_val
[0][xy
][1]*time_pb
/time_pp
;
919 s
->mv
[1][0][0] = s
->next_picture
.motion_val
[0][xy
][0]*(time_pb
- time_pp
)/time_pp
;
920 s
->mv
[1][0][1] = s
->next_picture
.motion_val
[0][xy
][1]*(time_pb
- time_pp
)/time_pp
;
928 s
->dsp
.clear_blocks(s
->block
[0]);
938 /* the filters below are not XvMC compatible, skip them */
939 if(s
->avctx
->xvmc_acceleration
) goto ec_clean
;
941 /* fill DC for inter blocks */
942 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
943 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
944 int dc
, dcu
, dcv
, y
, n
;
946 uint8_t *dest_y
, *dest_cb
, *dest_cr
;
947 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
948 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
950 error
= s
->error_status_table
[mb_xy
];
952 if(IS_INTRA(mb_type
) && s
->partitioned_frame
) continue;
953 // if(error&MV_ERROR) continue; //inter data damaged FIXME is this good?
955 dest_y
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
956 dest_cb
= s
->current_picture
.data
[1] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
957 dest_cr
= s
->current_picture
.data
[2] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
959 dc_ptr
= &s
->dc_val
[0][mb_x
*2 + mb_y
*2*s
->b8_stride
];
965 dc
+= dest_y
[x
+ (n
&1)*8 + (y
+ (n
>>1)*8)*s
->linesize
];
968 dc_ptr
[(n
&1) + (n
>>1)*s
->b8_stride
]= (dc
+4)>>3;
975 dcu
+=dest_cb
[x
+ y
*(s
->uvlinesize
)];
976 dcv
+=dest_cr
[x
+ y
*(s
->uvlinesize
)];
979 s
->dc_val
[1][mb_x
+ mb_y
*s
->mb_stride
]= (dcu
+4)>>3;
980 s
->dc_val
[2][mb_x
+ mb_y
*s
->mb_stride
]= (dcv
+4)>>3;
984 /* guess DC for damaged blocks */
985 guess_dc(s
, s
->dc_val
[0], s
->mb_width
*2, s
->mb_height
*2, s
->b8_stride
, 1);
986 guess_dc(s
, s
->dc_val
[1], s
->mb_width
, s
->mb_height
, s
->mb_stride
, 0);
987 guess_dc(s
, s
->dc_val
[2], s
->mb_width
, s
->mb_height
, s
->mb_stride
, 0);
990 filter181(s
->dc_val
[0], s
->mb_width
*2, s
->mb_height
*2, s
->b8_stride
);
993 /* render DC only intra */
994 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
995 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
996 uint8_t *dest_y
, *dest_cb
, *dest_cr
;
997 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
998 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
1000 error
= s
->error_status_table
[mb_xy
];
1002 if(IS_INTER(mb_type
)) continue;
1003 if(!(error
&AC_ERROR
)) continue; //undamaged
1005 dest_y
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
1006 dest_cb
= s
->current_picture
.data
[1] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
1007 dest_cr
= s
->current_picture
.data
[2] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
1009 put_dc(s
, dest_y
, dest_cb
, dest_cr
, mb_x
, mb_y
);
1014 if(s
->avctx
->error_concealment
&FF_EC_DEBLOCK
){
1015 /* filter horizontal block boundaries */
1016 h_block_filter(s
, s
->current_picture
.data
[0], s
->mb_width
*2, s
->mb_height
*2, s
->linesize
, 1);
1017 h_block_filter(s
, s
->current_picture
.data
[1], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
1018 h_block_filter(s
, s
->current_picture
.data
[2], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
1020 /* filter vertical block boundaries */
1021 v_block_filter(s
, s
->current_picture
.data
[0], s
->mb_width
*2, s
->mb_height
*2, s
->linesize
, 1);
1022 v_block_filter(s
, s
->current_picture
.data
[1], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
1023 v_block_filter(s
, s
->current_picture
.data
[2], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
1029 /* clean a few tables */
1030 for(i
=0; i
<s
->mb_num
; i
++){
1031 const int mb_xy
= s
->mb_index2xy
[i
];
1032 int error
= s
->error_status_table
[mb_xy
];
1034 if(s
->pict_type
!=FF_B_TYPE
&& (error
&(DC_ERROR
|MV_ERROR
|AC_ERROR
))){
1035 s
->mbskip_table
[mb_xy
]=0;
1037 s
->mbintra_table
[mb_xy
]=1;