2 * Error resilience / concealment
4 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * @file error_resilience.c
23 * Error resilience / concealment.
30 #include "mpegvideo.h"
33 static void decode_mb(MpegEncContext
*s
){
34 s
->dest
[0] = s
->current_picture
.data
[0] + (s
->mb_y
* 16* s
->linesize
) + s
->mb_x
* 16;
35 s
->dest
[1] = s
->current_picture
.data
[1] + (s
->mb_y
* 8 * s
->uvlinesize
) + s
->mb_x
* 8;
36 s
->dest
[2] = s
->current_picture
.data
[2] + (s
->mb_y
* 8 * s
->uvlinesize
) + s
->mb_x
* 8;
38 MPV_decode_mb(s
, s
->block
);
42 * replaces the current MB with a flat dc only version.
44 static void put_dc(MpegEncContext
*s
, uint8_t *dest_y
, uint8_t *dest_cb
, uint8_t *dest_cr
, int mb_x
, int mb_y
)
46 int dc
, dcu
, dcv
, y
, i
;
48 dc
= s
->dc_val
[0][mb_x
*2+1 + (i
&1) + (mb_y
*2+1 + (i
>>1))*(s
->mb_width
*2+2)];
50 else if(dc
>2040) dc
=2040;
54 dest_y
[x
+ (i
&1)*8 + (y
+ (i
>>1)*8)*s
->linesize
]= dc
/8;
58 dcu
= s
->dc_val
[1][mb_x
+1 + (mb_y
+1)*(s
->mb_width
+2)];
59 dcv
= s
->dc_val
[2][mb_x
+1 + (mb_y
+1)*(s
->mb_width
+2)];
61 else if(dcu
>2040) dcu
=2040;
63 else if(dcv
>2040) dcv
=2040;
67 dest_cb
[x
+ y
*(s
->uvlinesize
)]= dcu
/8;
68 dest_cr
[x
+ y
*(s
->uvlinesize
)]= dcv
/8;
73 static void filter181(int16_t *data
, int width
, int height
, int stride
){
76 /* horizontal filter */
77 for(y
=1; y
<height
-1; y
++){
78 int prev_dc
= data
[0 + y
*stride
];
80 for(x
=1; x
<width
-1; x
++){
84 + data
[x
+ y
*stride
]*8
85 - data
[x
+ 1 + y
*stride
];
86 dc
= (dc
*10923 + 32768)>>16;
87 prev_dc
= data
[x
+ y
*stride
];
88 data
[x
+ y
*stride
]= dc
;
93 for(x
=1; x
<width
-1; x
++){
96 for(y
=1; y
<height
-1; y
++){
100 + data
[x
+ y
*stride
]*8
101 - data
[x
+ (y
+1)*stride
];
102 dc
= (dc
*10923 + 32768)>>16;
103 prev_dc
= data
[x
+ y
*stride
];
104 data
[x
+ y
*stride
]= dc
;
110 * guess the dc of blocks which dont have a undamaged dc
111 * @param w width in 8 pixel blocks
112 * @param h height in 8 pixel blocks
114 static void guess_dc(MpegEncContext
*s
, int16_t *dc
, int w
, int h
, int stride
, int is_luma
){
117 for(b_y
=0; b_y
<h
; b_y
++){
118 for(b_x
=0; b_x
<w
; b_x
++){
119 int color
[4]={1024,1024,1024,1024};
120 int distance
[4]={9999,9999,9999,9999};
121 int mb_index
, error
, j
;
122 int64_t guess
, weight_sum
;
124 mb_index
= (b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
126 error
= s
->error_status_table
[mb_index
];
128 if(IS_INTER(s
->current_picture
.mb_type
[mb_index
])) continue; //inter
129 if(!(error
&DC_ERROR
)) continue; //dc-ok
132 for(j
=b_x
+1; j
<w
; j
++){
133 int mb_index_j
= (j
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
134 int error_j
= s
->error_status_table
[mb_index_j
];
135 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
136 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
137 color
[0]= dc
[j
+ b_y
*stride
];
144 for(j
=b_x
-1; j
>=0; j
--){
145 int mb_index_j
= (j
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
;
146 int error_j
= s
->error_status_table
[mb_index_j
];
147 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
148 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
149 color
[1]= dc
[j
+ b_y
*stride
];
156 for(j
=b_y
+1; j
<h
; j
++){
157 int mb_index_j
= (b_x
>>is_luma
) + (j
>>is_luma
)*s
->mb_stride
;
158 int error_j
= s
->error_status_table
[mb_index_j
];
159 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
160 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
161 color
[2]= dc
[b_x
+ j
*stride
];
168 for(j
=b_y
-1; j
>=0; j
--){
169 int mb_index_j
= (b_x
>>is_luma
) + (j
>>is_luma
)*s
->mb_stride
;
170 int error_j
= s
->error_status_table
[mb_index_j
];
171 int intra_j
= IS_INTRA(s
->current_picture
.mb_type
[mb_index_j
]);
172 if(intra_j
==0 || !(error_j
&DC_ERROR
)){
173 color
[3]= dc
[b_x
+ j
*stride
];
182 int64_t weight
= 256*256*256*16/distance
[j
];
183 guess
+= weight
*(int64_t)color
[j
];
186 guess
= (guess
+ weight_sum
/2) / weight_sum
;
188 dc
[b_x
+ b_y
*stride
]= guess
;
194 * simple horizontal deblocking filter used for error resilience
195 * @param w width in 8 pixel blocks
196 * @param h height in 8 pixel blocks
198 static void h_block_filter(MpegEncContext
*s
, uint8_t *dst
, int w
, int h
, int stride
, int is_luma
){
200 uint8_t *cm
= cropTbl
+ MAX_NEG_CROP
;
202 for(b_y
=0; b_y
<h
; b_y
++){
203 for(b_x
=0; b_x
<w
-1; b_x
++){
205 int left_status
= s
->error_status_table
[( b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
];
206 int right_status
= s
->error_status_table
[((b_x
+1)>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
];
207 int left_intra
= IS_INTRA(s
->current_picture
.mb_type
[( b_x
>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
]);
208 int right_intra
= IS_INTRA(s
->current_picture
.mb_type
[((b_x
+1)>>is_luma
) + (b_y
>>is_luma
)*s
->mb_stride
]);
209 int left_damage
= left_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
210 int right_damage
= right_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
211 int offset
= b_x
*8 + b_y
*stride
*8;
212 int16_t *left_mv
= s
->current_picture
.motion_val
[0][s
->block_wrap
[0]*((b_y
<<(1-is_luma
)) + 1) + ( b_x
<<(1-is_luma
))];
213 int16_t *right_mv
= s
->current_picture
.motion_val
[0][s
->block_wrap
[0]*((b_y
<<(1-is_luma
)) + 1) + ((b_x
+1)<<(1-is_luma
))];
215 if(!(left_damage
||right_damage
)) continue; // both undamaged
217 if( (!left_intra
) && (!right_intra
)
218 && ABS(left_mv
[0]-right_mv
[0]) + ABS(left_mv
[1]+right_mv
[1]) < 2) continue;
223 a
= dst
[offset
+ 7 + y
*stride
] - dst
[offset
+ 6 + y
*stride
];
224 b
= dst
[offset
+ 8 + y
*stride
] - dst
[offset
+ 7 + y
*stride
];
225 c
= dst
[offset
+ 9 + y
*stride
] - dst
[offset
+ 8 + y
*stride
];
227 d
= ABS(b
) - ((ABS(a
) + ABS(c
) + 1)>>1);
233 if(!(left_damage
&& right_damage
))
237 dst
[offset
+ 7 + y
*stride
] = cm
[dst
[offset
+ 7 + y
*stride
] + ((d
*7)>>4)];
238 dst
[offset
+ 6 + y
*stride
] = cm
[dst
[offset
+ 6 + y
*stride
] + ((d
*5)>>4)];
239 dst
[offset
+ 5 + y
*stride
] = cm
[dst
[offset
+ 5 + y
*stride
] + ((d
*3)>>4)];
240 dst
[offset
+ 4 + y
*stride
] = cm
[dst
[offset
+ 4 + y
*stride
] + ((d
*1)>>4)];
243 dst
[offset
+ 8 + y
*stride
] = cm
[dst
[offset
+ 8 + y
*stride
] - ((d
*7)>>4)];
244 dst
[offset
+ 9 + y
*stride
] = cm
[dst
[offset
+ 9 + y
*stride
] - ((d
*5)>>4)];
245 dst
[offset
+ 10+ y
*stride
] = cm
[dst
[offset
+10 + y
*stride
] - ((d
*3)>>4)];
246 dst
[offset
+ 11+ y
*stride
] = cm
[dst
[offset
+11 + y
*stride
] - ((d
*1)>>4)];
254 * simple vertical deblocking filter used for error resilience
255 * @param w width in 8 pixel blocks
256 * @param h height in 8 pixel blocks
258 static void v_block_filter(MpegEncContext
*s
, uint8_t *dst
, int w
, int h
, int stride
, int is_luma
){
260 uint8_t *cm
= cropTbl
+ MAX_NEG_CROP
;
262 for(b_y
=0; b_y
<h
-1; b_y
++){
263 for(b_x
=0; b_x
<w
; b_x
++){
265 int top_status
= s
->error_status_table
[(b_x
>>is_luma
) + ( b_y
>>is_luma
)*s
->mb_stride
];
266 int bottom_status
= s
->error_status_table
[(b_x
>>is_luma
) + ((b_y
+1)>>is_luma
)*s
->mb_stride
];
267 int top_intra
= IS_INTRA(s
->current_picture
.mb_type
[(b_x
>>is_luma
) + ( b_y
>>is_luma
)*s
->mb_stride
]);
268 int bottom_intra
= IS_INTRA(s
->current_picture
.mb_type
[(b_x
>>is_luma
) + ((b_y
+1)>>is_luma
)*s
->mb_stride
]);
269 int top_damage
= top_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
270 int bottom_damage
= bottom_status
&(DC_ERROR
|AC_ERROR
|MV_ERROR
);
271 int offset
= b_x
*8 + b_y
*stride
*8;
272 int16_t *top_mv
= s
->current_picture
.motion_val
[0][s
->block_wrap
[0]*(( b_y
<<(1-is_luma
)) + 1) + (b_x
<<(1-is_luma
))];
273 int16_t *bottom_mv
= s
->current_picture
.motion_val
[0][s
->block_wrap
[0]*(((b_y
+1)<<(1-is_luma
)) + 1) + (b_x
<<(1-is_luma
))];
275 if(!(top_damage
||bottom_damage
)) continue; // both undamaged
277 if( (!top_intra
) && (!bottom_intra
)
278 && ABS(top_mv
[0]-bottom_mv
[0]) + ABS(top_mv
[1]+bottom_mv
[1]) < 2) continue;
283 a
= dst
[offset
+ x
+ 7*stride
] - dst
[offset
+ x
+ 6*stride
];
284 b
= dst
[offset
+ x
+ 8*stride
] - dst
[offset
+ x
+ 7*stride
];
285 c
= dst
[offset
+ x
+ 9*stride
] - dst
[offset
+ x
+ 8*stride
];
287 d
= ABS(b
) - ((ABS(a
) + ABS(c
)+1)>>1);
293 if(!(top_damage
&& bottom_damage
))
297 dst
[offset
+ x
+ 7*stride
] = cm
[dst
[offset
+ x
+ 7*stride
] + ((d
*7)>>4)];
298 dst
[offset
+ x
+ 6*stride
] = cm
[dst
[offset
+ x
+ 6*stride
] + ((d
*5)>>4)];
299 dst
[offset
+ x
+ 5*stride
] = cm
[dst
[offset
+ x
+ 5*stride
] + ((d
*3)>>4)];
300 dst
[offset
+ x
+ 4*stride
] = cm
[dst
[offset
+ x
+ 4*stride
] + ((d
*1)>>4)];
303 dst
[offset
+ x
+ 8*stride
] = cm
[dst
[offset
+ x
+ 8*stride
] - ((d
*7)>>4)];
304 dst
[offset
+ x
+ 9*stride
] = cm
[dst
[offset
+ x
+ 9*stride
] - ((d
*5)>>4)];
305 dst
[offset
+ x
+ 10*stride
] = cm
[dst
[offset
+ x
+ 10*stride
] - ((d
*3)>>4)];
306 dst
[offset
+ x
+ 11*stride
] = cm
[dst
[offset
+ x
+ 11*stride
] - ((d
*1)>>4)];
313 static void guess_mv(MpegEncContext
*s
){
314 uint8_t fixed
[s
->mb_stride
* s
->mb_height
];
317 #define MV_UNCHANGED 1
318 const int mb_stride
= s
->mb_stride
;
319 const int mb_width
= s
->mb_width
;
320 const int mb_height
= s
->mb_height
;
321 int i
, depth
, num_avail
;
325 for(i
=0; i
<s
->mb_num
; i
++){
326 const int mb_xy
= s
->mb_index2xy
[ i
];
328 int error
= s
->error_status_table
[mb_xy
];
330 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
])) f
=MV_FROZEN
; //intra //FIXME check
331 if(!(error
&MV_ERROR
)) f
=MV_FROZEN
; //inter with undamaged MV
338 if((!(s
->avctx
->error_concealment
&FF_EC_GUESS_MVS
)) || num_avail
<= mb_width
/2){
339 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
340 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
341 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
343 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
])) continue;
344 if(!(s
->error_status_table
[mb_xy
]&MV_ERROR
)) continue;
346 s
->mv_dir
= MV_DIR_FORWARD
;
348 s
->mv_type
= MV_TYPE_16X16
;
351 s
->dsp
.clear_blocks(s
->block
[0]);
363 for(depth
=0;; depth
++){
364 int changed
, pass
, none_left
;
368 for(pass
=0; (changed
|| pass
<2) && pass
<10; pass
++){
373 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
374 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
375 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
376 int mv_predictor
[8][2]={{0}};
379 int best_score
=256*256*256*64;
381 const int mot_stride
= mb_width
*2+2;
382 const int mot_index
= mb_x
*2 + 1 + (mb_y
*2+1)*mot_stride
;
383 int prev_x
= s
->current_picture
.motion_val
[0][mot_index
][0];
384 int prev_y
= s
->current_picture
.motion_val
[0][mot_index
][1];
386 if((mb_x
^mb_y
^pass
)&1) continue;
388 if(fixed
[mb_xy
]==MV_FROZEN
) continue;
389 assert(!IS_INTRA(s
->current_picture
.mb_type
[mb_xy
]));
390 assert(s
->last_picture_ptr
&& s
->last_picture_ptr
->data
[0]);
393 if(mb_x
>0 && fixed
[mb_xy
-1 ]==MV_FROZEN
) j
=1;
394 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1 ]==MV_FROZEN
) j
=1;
395 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]==MV_FROZEN
) j
=1;
396 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]==MV_FROZEN
) j
=1;
400 if(mb_x
>0 && fixed
[mb_xy
-1 ]==MV_CHANGED
) j
=1;
401 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1 ]==MV_CHANGED
) j
=1;
402 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]==MV_CHANGED
) j
=1;
403 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]==MV_CHANGED
) j
=1;
404 if(j
==0 && pass
>1) continue;
408 if(mb_x
>0 && fixed
[mb_xy
-1]){
409 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
- 2][0];
410 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
- 2][1];
413 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1]){
414 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
+ 2][0];
415 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
+ 2][1];
418 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]){
419 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
- mot_stride
*2][0];
420 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
- mot_stride
*2][1];
423 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]){
424 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
+ mot_stride
*2][0];
425 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
+ mot_stride
*2][1];
428 if(pred_count
==0) continue;
431 int sum_x
=0, sum_y
=0;
432 int max_x
, max_y
, min_x
, min_y
;
434 for(j
=0; j
<pred_count
; j
++){
435 sum_x
+= mv_predictor
[j
][0];
436 sum_y
+= mv_predictor
[j
][1];
440 mv_predictor
[pred_count
][0] = sum_x
/j
;
441 mv_predictor
[pred_count
][1] = sum_y
/j
;
448 min_x
=min_y
=max_x
=max_y
=0;
450 for(j
=0; j
<pred_count
; j
++){
451 max_x
= FFMAX(max_x
, mv_predictor
[j
][0]);
452 max_y
= FFMAX(max_y
, mv_predictor
[j
][1]);
453 min_x
= FFMIN(min_x
, mv_predictor
[j
][0]);
454 min_y
= FFMIN(min_y
, mv_predictor
[j
][1]);
456 mv_predictor
[pred_count
+1][0] = sum_x
- max_x
- min_x
;
457 mv_predictor
[pred_count
+1][1] = sum_y
- max_y
- min_y
;
460 mv_predictor
[pred_count
+1][0] /= 2;
461 mv_predictor
[pred_count
+1][1] /= 2;
470 mv_predictor
[pred_count
][0]= s
->current_picture
.motion_val
[0][mot_index
][0];
471 mv_predictor
[pred_count
][1]= s
->current_picture
.motion_val
[0][mot_index
][1];
474 s
->mv_dir
= MV_DIR_FORWARD
;
476 s
->mv_type
= MV_TYPE_16X16
;
479 s
->dsp
.clear_blocks(s
->block
[0]);
484 for(j
=0; j
<pred_count
; j
++){
486 uint8_t *src
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
488 s
->current_picture
.motion_val
[0][mot_index
][0]= s
->mv
[0][0][0]= mv_predictor
[j
][0];
489 s
->current_picture
.motion_val
[0][mot_index
][1]= s
->mv
[0][0][1]= mv_predictor
[j
][1];
493 if(mb_x
>0 && fixed
[mb_xy
-1]){
496 score
+= ABS(src
[k
*s
->linesize
-1 ]-src
[k
*s
->linesize
]);
498 if(mb_x
+1<mb_width
&& fixed
[mb_xy
+1]){
501 score
+= ABS(src
[k
*s
->linesize
+15]-src
[k
*s
->linesize
+16]);
503 if(mb_y
>0 && fixed
[mb_xy
-mb_stride
]){
506 score
+= ABS(src
[k
-s
->linesize
]-src
[k
]);
508 if(mb_y
+1<mb_height
&& fixed
[mb_xy
+mb_stride
]){
511 score
+= ABS(src
[k
+s
->linesize
*15]-src
[k
+s
->linesize
*16]);
514 if(score
<= best_score
){ // <= will favor the last MV
519 score_sum
+= best_score
;
520 //FIXME no need to set s->current_picture.motion_val[0][mot_index][0] explicit
521 s
->current_picture
.motion_val
[0][mot_index
][0]= s
->mv
[0][0][0]= mv_predictor
[best_pred
][0];
522 s
->current_picture
.motion_val
[0][mot_index
][1]= s
->mv
[0][0][1]= mv_predictor
[best_pred
][1];
527 if(s
->mv
[0][0][0] != prev_x
|| s
->mv
[0][0][1] != prev_y
){
528 fixed
[mb_xy
]=MV_CHANGED
;
531 fixed
[mb_xy
]=MV_UNCHANGED
;
535 // printf(".%d/%d", changed, score_sum); fflush(stdout);
541 for(i
=0; i
<s
->mb_num
; i
++){
542 int mb_xy
= s
->mb_index2xy
[i
];
544 fixed
[mb_xy
]=MV_FROZEN
;
546 // printf(":"); fflush(stdout);
550 static int is_intra_more_likely(MpegEncContext
*s
){
551 int is_intra_likely
, i
, j
, undamaged_count
, skip_amount
, mb_x
, mb_y
;
553 if(s
->last_picture_ptr
==NULL
) return 1; //no previous frame available -> use spatial prediction
556 for(i
=0; i
<s
->mb_num
; i
++){
557 const int mb_xy
= s
->mb_index2xy
[i
];
558 const int error
= s
->error_status_table
[mb_xy
];
559 if(!((error
&DC_ERROR
) && (error
&MV_ERROR
)))
563 if(undamaged_count
< 5) return 0; //allmost all MBs damaged -> use temporal prediction
565 skip_amount
= FFMAX(undamaged_count
/50, 1); //check only upto 50 MBs
569 for(mb_y
= 0; mb_y
<s
->mb_height
-1; mb_y
++){
570 for(mb_x
= 0; mb_x
<s
->mb_width
; mb_x
++){
572 const int mb_xy
= mb_x
+ mb_y
*s
->mb_stride
;
574 error
= s
->error_status_table
[mb_xy
];
575 if((error
&DC_ERROR
) && (error
&MV_ERROR
))
576 continue; //skip damaged
579 if((j
%skip_amount
) != 0) continue; //skip a few to speed things up
581 if(s
->pict_type
==I_TYPE
){
582 uint8_t *mb_ptr
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
583 uint8_t *last_mb_ptr
= s
->last_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
585 is_intra_likely
+= s
->dsp
.sad
[0](NULL
, last_mb_ptr
, mb_ptr
, s
->linesize
, 16);
586 is_intra_likely
-= s
->dsp
.sad
[0](NULL
, last_mb_ptr
, last_mb_ptr
+s
->linesize
*16, s
->linesize
, 16);
588 if(IS_INTRA(s
->current_picture
.mb_type
[mb_xy
]))
595 //printf("is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
596 return is_intra_likely
> 0;
599 void ff_er_frame_start(MpegEncContext
*s
){
600 if(!s
->error_resilience
) return;
602 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));
603 s
->error_count
= 3*s
->mb_num
;
608 * @param endx x component of the last macroblock, can be -1 for the last of the previous line
609 * @param status the status at the end (MV_END, AC_ERROR, ...), it is assumed that no earlier end or
610 * error of the same type occured
612 void ff_er_add_slice(MpegEncContext
*s
, int startx
, int starty
, int endx
, int endy
, int status
){
613 const int start_i
= clip(startx
+ starty
* s
->mb_width
, 0, s
->mb_num
-1);
614 const int end_i
= clip(endx
+ endy
* s
->mb_width
, 0, s
->mb_num
);
615 const int start_xy
= s
->mb_index2xy
[start_i
];
616 const int end_xy
= s
->mb_index2xy
[end_i
];
619 if(!s
->error_resilience
) return;
622 if(status
& (AC_ERROR
|AC_END
)){
623 mask
&= ~(AC_ERROR
|AC_END
);
624 s
->error_count
-= end_i
- start_i
+ 1;
626 if(status
& (DC_ERROR
|DC_END
)){
627 mask
&= ~(DC_ERROR
|DC_END
);
628 s
->error_count
-= end_i
- start_i
+ 1;
630 if(status
& (MV_ERROR
|MV_END
)){
631 mask
&= ~(MV_ERROR
|MV_END
);
632 s
->error_count
-= end_i
- start_i
+ 1;
635 if(status
& (AC_ERROR
|DC_ERROR
|MV_ERROR
)) s
->error_count
= INT_MAX
;
638 memset(&s
->error_status_table
[start_xy
], 0, (end_xy
- start_xy
) * sizeof(uint8_t));
641 for(i
=start_xy
; i
<end_xy
; i
++){
642 s
->error_status_table
[ i
] &= mask
;
646 if(end_i
== s
->mb_num
)
647 s
->error_count
= INT_MAX
;
649 s
->error_status_table
[end_xy
] &= mask
;
650 s
->error_status_table
[end_xy
] |= status
;
653 s
->error_status_table
[start_xy
] |= VP_START
;
656 int prev_status
= s
->error_status_table
[ s
->mb_index2xy
[start_i
- 1] ];
658 prev_status
&= ~ VP_START
;
659 if(prev_status
!= (MV_END
|DC_END
|AC_END
)) s
->error_count
= INT_MAX
;
663 void ff_er_frame_end(MpegEncContext
*s
){
664 int i
, mb_x
, mb_y
, error
, error_type
;
666 int threshold_part
[4]= {100,100,100};
670 if(!s
->error_resilience
|| s
->error_count
==0) return;
672 av_log(s
->avctx
, AV_LOG_INFO
, "concealing errors\n");
674 if(s
->current_picture
.motion_val
[0] == NULL
){
675 int size
= (2 * s
->mb_width
+ 2) * (2 * s
->mb_height
+ 2);
677 av_log(s
->avctx
, AV_LOG_ERROR
, "Warning MVs not available\n");
679 s
->current_picture
.motion_val
[0]= av_mallocz(size
* 2 * sizeof(int16_t)); //FIXME
680 s
->current_picture
.motion_val
[1]= av_mallocz(size
* 2 * sizeof(int16_t));
683 if(s
->avctx
->debug
&FF_DEBUG_ER
){
684 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
685 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
686 int status
= s
->error_status_table
[mb_x
+ mb_y
*s
->mb_stride
];
688 av_log(s
->avctx
, AV_LOG_DEBUG
, "%2X ", status
);
690 av_log(s
->avctx
, AV_LOG_DEBUG
, "\n");
695 /* handle overlapping slices */
696 for(error_type
=1; error_type
<=3; error_type
++){
699 for(i
=s
->mb_num
-1; i
>=0; i
--){
700 const int mb_xy
= s
->mb_index2xy
[i
];
701 int error
= s
->error_status_table
[mb_xy
];
703 if(error
&(1<<error_type
))
705 if(error
&(8<<error_type
))
709 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
717 /* handle slices with partitions of different length */
718 if(s
->partitioned_frame
){
721 for(i
=s
->mb_num
-1; i
>=0; i
--){
722 const int mb_xy
= s
->mb_index2xy
[i
];
723 int error
= s
->error_status_table
[mb_xy
];
727 if((error
&MV_END
) || (error
&DC_END
) || (error
&AC_ERROR
))
731 s
->error_status_table
[mb_xy
]|= AC_ERROR
;
738 /* handle missing slices */
739 if(s
->error_resilience
>=4){
742 for(i
=s
->mb_num
-2; i
>=s
->mb_width
+100; i
--){ //FIXME +100 hack
743 const int mb_xy
= s
->mb_index2xy
[i
];
744 int error1
= s
->error_status_table
[mb_xy
];
745 int error2
= s
->error_status_table
[s
->mb_index2xy
[i
+1]];
750 if( error2
==(VP_START
|DC_ERROR
|AC_ERROR
|MV_ERROR
|AC_END
|DC_END
|MV_END
)
751 && error1
!=(VP_START
|DC_ERROR
|AC_ERROR
|MV_ERROR
|AC_END
|DC_END
|MV_END
)
752 && ((error1
&AC_END
) || (error1
&DC_END
) || (error1
&MV_END
))){ //end & uninited
757 s
->error_status_table
[mb_xy
]|= DC_ERROR
|AC_ERROR
|MV_ERROR
;
762 /* backward mark errors */
764 for(error_type
=1; error_type
<=3; error_type
++){
765 for(i
=s
->mb_num
-1; i
>=0; i
--){
766 const int mb_xy
= s
->mb_index2xy
[i
];
767 int error
= s
->error_status_table
[mb_xy
];
769 if(!s
->mbskip_table
[mb_xy
]) //FIXME partition specific
771 if(error
&(1<<error_type
))
774 if(s
->partitioned_frame
){
775 if(distance
< threshold_part
[error_type
-1])
776 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
778 if(distance
< threshold
)
779 s
->error_status_table
[mb_xy
]|= 1<<error_type
;
788 /* forward mark errors */
790 for(i
=0; i
<s
->mb_num
; i
++){
791 const int mb_xy
= s
->mb_index2xy
[i
];
792 int old_error
= s
->error_status_table
[mb_xy
];
794 if(old_error
&VP_START
)
795 error
= old_error
& (DC_ERROR
|AC_ERROR
|MV_ERROR
);
797 error
|= old_error
& (DC_ERROR
|AC_ERROR
|MV_ERROR
);
798 s
->error_status_table
[mb_xy
]|= error
;
802 /* handle not partitioned case */
803 if(!s
->partitioned_frame
){
804 for(i
=0; i
<s
->mb_num
; i
++){
805 const int mb_xy
= s
->mb_index2xy
[i
];
806 error
= s
->error_status_table
[mb_xy
];
807 if(error
&(AC_ERROR
|DC_ERROR
|MV_ERROR
))
808 error
|= AC_ERROR
|DC_ERROR
|MV_ERROR
;
809 s
->error_status_table
[mb_xy
]= error
;
813 is_intra_likely
= is_intra_more_likely(s
);
815 /* set unknown mb-type to most likely */
816 for(i
=0; i
<s
->mb_num
; i
++){
817 const int mb_xy
= s
->mb_index2xy
[i
];
818 error
= s
->error_status_table
[mb_xy
];
819 if(!((error
&DC_ERROR
) && (error
&MV_ERROR
)))
823 s
->current_picture
.mb_type
[mb_xy
]= MB_TYPE_INTRA4x4
;
825 s
->current_picture
.mb_type
[mb_xy
]= MB_TYPE_16x16
| MB_TYPE_L0
;
828 /* handle inter blocks with damaged AC */
829 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
830 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
831 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
832 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
833 error
= s
->error_status_table
[mb_xy
];
835 if(IS_INTRA(mb_type
)) continue; //intra
836 if(error
&MV_ERROR
) continue; //inter with damaged MV
837 if(!(error
&AC_ERROR
)) continue; //undamaged inter
839 s
->mv_dir
= MV_DIR_FORWARD
;
843 int mb_index
= mb_x
*2+1 + (mb_y
*2+1)*s
->block_wrap
[0];
845 s
->mv_type
= MV_TYPE_8X8
;
847 s
->mv
[0][j
][0] = s
->current_picture
.motion_val
[0][ mb_index
+ (j
&1) + (j
>>1)*s
->block_wrap
[0] ][0];
848 s
->mv
[0][j
][1] = s
->current_picture
.motion_val
[0][ mb_index
+ (j
&1) + (j
>>1)*s
->block_wrap
[0] ][1];
851 s
->mv_type
= MV_TYPE_16X16
;
852 s
->mv
[0][0][0] = s
->current_picture
.motion_val
[0][ mb_x
*2+1 + (mb_y
*2+1)*s
->block_wrap
[0] ][0];
853 s
->mv
[0][0][1] = s
->current_picture
.motion_val
[0][ mb_x
*2+1 + (mb_y
*2+1)*s
->block_wrap
[0] ][1];
856 s
->dsp
.clear_blocks(s
->block
[0]);
865 if(s
->pict_type
==B_TYPE
){
866 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
867 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
868 int xy
= mb_x
*2+1 + (mb_y
*2+1)*s
->block_wrap
[0];
869 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
870 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
871 error
= s
->error_status_table
[mb_xy
];
873 if(IS_INTRA(mb_type
)) continue;
874 if(!(error
&MV_ERROR
)) continue; //inter with undamaged MV
875 if(!(error
&AC_ERROR
)) continue; //undamaged inter
877 s
->mv_dir
= MV_DIR_FORWARD
|MV_DIR_BACKWARD
;
879 s
->mv_type
= MV_TYPE_16X16
;
883 int time_pp
= s
->pp_time
;
884 int time_pb
= s
->pb_time
;
886 s
->mv
[0][0][0] = s
->next_picture
.motion_val
[0][xy
][0]*time_pb
/time_pp
;
887 s
->mv
[0][0][1] = s
->next_picture
.motion_val
[0][xy
][1]*time_pb
/time_pp
;
888 s
->mv
[1][0][0] = s
->next_picture
.motion_val
[0][xy
][0]*(time_pb
- time_pp
)/time_pp
;
889 s
->mv
[1][0][1] = s
->next_picture
.motion_val
[0][xy
][1]*(time_pb
- time_pp
)/time_pp
;
897 s
->dsp
.clear_blocks(s
->block
[0]);
907 /* the filters below are not XvMC compatible, skip them */
908 if(s
->avctx
->xvmc_acceleration
) goto ec_clean
;
910 /* fill DC for inter blocks */
911 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
912 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
913 int dc
, dcu
, dcv
, y
, n
;
915 uint8_t *dest_y
, *dest_cb
, *dest_cr
;
916 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
917 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
919 error
= s
->error_status_table
[mb_xy
];
921 if(IS_INTRA(mb_type
) && s
->partitioned_frame
) continue;
922 // if(error&MV_ERROR) continue; //inter data damaged FIXME is this good?
924 dest_y
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
925 dest_cb
= s
->current_picture
.data
[1] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
926 dest_cr
= s
->current_picture
.data
[2] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
928 dc_ptr
= &s
->dc_val
[0][mb_x
*2+1 + (mb_y
*2+1)*(s
->mb_width
*2+2)];
934 dc
+= dest_y
[x
+ (n
&1)*8 + (y
+ (n
>>1)*8)*s
->linesize
];
937 dc_ptr
[(n
&1) + (n
>>1)*(s
->mb_width
*2+2)]= (dc
+4)>>3;
944 dcu
+=dest_cb
[x
+ y
*(s
->uvlinesize
)];
945 dcv
+=dest_cr
[x
+ y
*(s
->uvlinesize
)];
948 s
->dc_val
[1][mb_x
+1 + (mb_y
+1)*(s
->mb_width
+2)]= (dcu
+4)>>3;
949 s
->dc_val
[2][mb_x
+1 + (mb_y
+1)*(s
->mb_width
+2)]= (dcv
+4)>>3;
953 /* guess DC for damaged blocks */
954 guess_dc(s
, s
->dc_val
[0] + s
->mb_width
*2+3, s
->mb_width
*2, s
->mb_height
*2, s
->mb_width
*2+2, 1);
955 guess_dc(s
, s
->dc_val
[1] + s
->mb_width
+3, s
->mb_width
, s
->mb_height
, s
->mb_width
+2, 0);
956 guess_dc(s
, s
->dc_val
[2] + s
->mb_width
+3, s
->mb_width
, s
->mb_height
, s
->mb_width
+2, 0);
959 filter181(s
->dc_val
[0] + s
->mb_width
*2+3, s
->mb_width
*2, s
->mb_height
*2, s
->mb_width
*2+2);
962 /* render DC only intra */
963 for(mb_y
=0; mb_y
<s
->mb_height
; mb_y
++){
964 for(mb_x
=0; mb_x
<s
->mb_width
; mb_x
++){
965 uint8_t *dest_y
, *dest_cb
, *dest_cr
;
966 const int mb_xy
= mb_x
+ mb_y
* s
->mb_stride
;
967 const int mb_type
= s
->current_picture
.mb_type
[mb_xy
];
969 error
= s
->error_status_table
[mb_xy
];
971 if(IS_INTER(mb_type
)) continue;
972 if(!(error
&AC_ERROR
)) continue; //undamaged
974 dest_y
= s
->current_picture
.data
[0] + mb_x
*16 + mb_y
*16*s
->linesize
;
975 dest_cb
= s
->current_picture
.data
[1] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
976 dest_cr
= s
->current_picture
.data
[2] + mb_x
*8 + mb_y
*8 *s
->uvlinesize
;
978 put_dc(s
, dest_y
, dest_cb
, dest_cr
, mb_x
, mb_y
);
983 if(s
->avctx
->error_concealment
&FF_EC_DEBLOCK
){
984 /* filter horizontal block boundaries */
985 h_block_filter(s
, s
->current_picture
.data
[0], s
->mb_width
*2, s
->mb_height
*2, s
->linesize
, 1);
986 h_block_filter(s
, s
->current_picture
.data
[1], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
987 h_block_filter(s
, s
->current_picture
.data
[2], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
989 /* filter vertical block boundaries */
990 v_block_filter(s
, s
->current_picture
.data
[0], s
->mb_width
*2, s
->mb_height
*2, s
->linesize
, 1);
991 v_block_filter(s
, s
->current_picture
.data
[1], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
992 v_block_filter(s
, s
->current_picture
.data
[2], s
->mb_width
, s
->mb_height
, s
->uvlinesize
, 0);
998 /* clean a few tables */
999 for(i
=0; i
<s
->mb_num
; i
++){
1000 const int mb_xy
= s
->mb_index2xy
[i
];
1001 int error
= s
->error_status_table
[mb_xy
];
1003 if(s
->pict_type
!=B_TYPE
&& (error
&(DC_ERROR
|MV_ERROR
|AC_ERROR
))){
1004 s
->mbskip_table
[mb_xy
]=0;
1006 s
->mbintra_table
[mb_xy
]=1;