summaryrefslogtreecommitdiff
path: root/libavcodec/mpegvideo.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/mpegvideo.c')
-rw-r--r--libavcodec/mpegvideo.c301
1 files changed, 189 insertions, 112 deletions
diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
index 63338012ff..f947634c2c 100644
--- a/libavcodec/mpegvideo.c
+++ b/libavcodec/mpegvideo.c
@@ -268,40 +268,87 @@ int DCT_common_init(MpegEncContext *s)
}
/**
- * allocates various arrays for a Picture structure, except the pixels themself.
- * The pixels are allocated/set in te get_buffer()
+ * allocates a Picture
+ * The pixels are allocated/set by calling get_buffer() if shared=0
*/
-static int alloc_picture(MpegEncContext *s, Picture *pic){
- if (s->encoding) {
- CHECKED_ALLOCZ(pic->mb_var , s->mb_num * sizeof(INT16))
- CHECKED_ALLOCZ(pic->mc_mb_var, s->mb_num * sizeof(INT16))
- CHECKED_ALLOCZ(pic->mb_mean , s->mb_num * sizeof(INT8))
+static int alloc_picture(MpegEncContext *s, Picture *pic, int shared){
+
+ if(shared){
+ assert(pic->data[0]);
+ assert(pic->type == 0 || pic->type == FF_BUFFER_TYPE_SHARED);
+ pic->type= FF_BUFFER_TYPE_SHARED;
+ }else{
+ int r;
+
+ assert(!pic->data[0]);
+
+ r= s->avctx->get_buffer(s->avctx, (AVVideoFrame*)pic);
+
+ if(r<0 || !pic->age || !pic->type || !pic->data[0]){
+ fprintf(stderr, "get_buffer() failed (%d %d %d %X)\n", r, pic->age, pic->type, (int)pic->data[0]);
+ return -1;
+ }
+
+ if(s->linesize && (s->linesize != pic->linesize[0] || s->uvlinesize != pic->linesize[1])){
+ fprintf(stderr, "get_buffer() failed (stride changed)\n");
+ return -1;
+ }
+
+ if(pic->linesize[1] != pic->linesize[2]){
+ fprintf(stderr, "get_buffer() failed (uv stride missmatch)\n");
+ return -1;
+ }
+
+ s->linesize = pic->linesize[0];
+ s->uvlinesize= pic->linesize[1];
}
+
+ if(pic->qscale_table==NULL){
+ if (s->encoding) {
+ CHECKED_ALLOCZ(pic->mb_var , s->mb_num * sizeof(INT16))
+ CHECKED_ALLOCZ(pic->mc_mb_var, s->mb_num * sizeof(INT16))
+ CHECKED_ALLOCZ(pic->mb_mean , s->mb_num * sizeof(INT8))
+ }
- CHECKED_ALLOCZ(pic->mbskip_table , s->mb_num * sizeof(UINT8)+1) //the +1 is for the slice end check
- CHECKED_ALLOCZ(pic->qscale_table , s->mb_num * sizeof(UINT8))
- pic->qstride= s->mb_width;
+ CHECKED_ALLOCZ(pic->mbskip_table , s->mb_num * sizeof(UINT8)+1) //the +1 is for the slice end check
+ CHECKED_ALLOCZ(pic->qscale_table , s->mb_num * sizeof(UINT8))
+ pic->qstride= s->mb_width;
+ }
return 0;
fail: //for the CHECKED_ALLOCZ macro
return -1;
}
+/**
+ * deallocates a picture
+ */
static void free_picture(MpegEncContext *s, Picture *pic){
int i;
-
+
+ if(pic->data[0] && pic->type!=FF_BUFFER_TYPE_SHARED){
+ s->avctx->release_buffer(s->avctx, (AVVideoFrame*)pic);
+ }
+
av_freep(&pic->mb_var);
av_freep(&pic->mc_mb_var);
av_freep(&pic->mb_mean);
av_freep(&pic->mbskip_table);
av_freep(&pic->qscale_table);
- if(s->avctx->get_buffer == avcodec_default_get_buffer){
+ if(pic->type == FF_BUFFER_TYPE_INTERNAL){
for(i=0; i<4; i++){
av_freep(&pic->base[i]);
pic->data[i]= NULL;
}
av_freep(&pic->opaque);
+ pic->type= 0;
+ }else if(pic->type == FF_BUFFER_TYPE_SHARED){
+ for(i=0; i<4; i++){
+ pic->base[i]=
+ pic->data[i]= NULL;
+ }
+ pic->type= 0;
}
}
@@ -445,12 +492,6 @@ void MPV_common_end(MpegEncContext *s)
{
int i;
- for(i=0; i<MAX_PICTURE_COUNT; i++){
- if(s->picture[i].data[0]){
- s->avctx->release_buffer(s->avctx, (AVVideoFrame*)&s->picture[i]);
- }
- }
-
av_freep(&s->mb_type);
av_freep(&s->p_mv_table);
av_freep(&s->b_forw_mv_table);
@@ -572,6 +613,7 @@ int MPV_encode_init(AVCodecContext *avctx)
if (mjpeg_init(s) < 0)
return -1;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_H263:
if (h263_get_picture_format(s->width, s->height) == 7) {
@@ -580,6 +622,7 @@ int MPV_encode_init(AVCodecContext *avctx)
}
s->out_format = FMT_H263;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_H263P:
s->out_format = FMT_H263;
@@ -591,18 +634,19 @@ int MPV_encode_init(AVCodecContext *avctx)
s->umvplus = 0;
s->umvplus_dec = 0;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_RV10:
s->out_format = FMT_H263;
s->h263_rv10 = 1;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_MPEG4:
s->out_format = FMT_H263;
s->h263_pred = 1;
s->unrestricted_mv = 1;
- s->has_b_frames= s->max_b_frames ? 1 : 0;
- s->low_delay= !s->has_b_frames;
+ s->low_delay= s->max_b_frames ? 0 : 1;
avctx->delay= s->low_delay ? 0 : (s->max_b_frames + 1);
break;
case CODEC_ID_MSMPEG4V1:
@@ -612,6 +656,7 @@ int MPV_encode_init(AVCodecContext *avctx)
s->unrestricted_mv = 1;
s->msmpeg4_version= 1;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_MSMPEG4V2:
s->out_format = FMT_H263;
@@ -620,6 +665,7 @@ int MPV_encode_init(AVCodecContext *avctx)
s->unrestricted_mv = 1;
s->msmpeg4_version= 2;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_MSMPEG4V3:
s->out_format = FMT_H263;
@@ -628,6 +674,7 @@ int MPV_encode_init(AVCodecContext *avctx)
s->unrestricted_mv = 1;
s->msmpeg4_version= 3;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_WMV1:
s->out_format = FMT_H263;
@@ -636,6 +683,7 @@ int MPV_encode_init(AVCodecContext *avctx)
s->unrestricted_mv = 1;
s->msmpeg4_version= 4;
avctx->delay=0;
+ s->low_delay=1;
break;
case CODEC_ID_WMV2:
s->out_format = FMT_H263;
@@ -644,6 +692,7 @@ int MPV_encode_init(AVCodecContext *avctx)
s->unrestricted_mv = 1;
s->msmpeg4_version= 5;
avctx->delay=0;
+ s->low_delay=1;
break;
default:
return -1;
@@ -770,10 +819,30 @@ static void draw_edges_c(UINT8 *buf, int wrap, int width, int height, int w)
}
}
+static int find_unused_picture(MpegEncContext *s, int shared){
+ int i;
+
+ if(shared){
+ for(i=0; i<MAX_PICTURE_COUNT; i++){
+ if(s->picture[i].data[0]==NULL && s->picture[i].type==0) break;
+ }
+ }else{
+ for(i=0; i<MAX_PICTURE_COUNT; i++){
+ if(s->picture[i].data[0]==NULL && s->picture[i].type!=0) break;
+ }
+ for(i=0; i<MAX_PICTURE_COUNT; i++){
+ if(s->picture[i].data[0]==NULL) break;
+ }
+ }
+
+ assert(i<MAX_PICTURE_COUNT);
+ return i;
+}
+
/* generic function for encode/decode called before a frame is coded/decoded */
int MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
{
- int i, r;
+ int i;
AVVideoFrame *pic;
s->mb_skiped = 0;
@@ -781,6 +850,7 @@ int MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
/* mark&release old frames */
if (s->pict_type != B_TYPE && s->last_picture.data[0]) {
for(i=0; i<MAX_PICTURE_COUNT; i++){
+//printf("%8X %d %d %X %X\n", s->picture[i].data[0], s->picture[i].type, i, s->next_picture.data[0], s->last_picture.data[0]);
if(s->picture[i].data[0] == s->last_picture.data[0]){
// s->picture[i].reference=0;
avctx->release_buffer(avctx, (AVVideoFrame*)&s->picture[i]);
@@ -802,28 +872,13 @@ int MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
}
alloc:
if(!s->encoding){
- /* find unused Picture */
- for(i=0; i<MAX_PICTURE_COUNT; i++){
- if(s->picture[i].data[0]==NULL) break;
- }
- assert(i<MAX_PICTURE_COUNT);
+ i= find_unused_picture(s, 0);
pic= (AVVideoFrame*)&s->picture[i];
pic->reference= s->pict_type != B_TYPE;
pic->coded_picture_number= s->current_picture.coded_picture_number+1;
- r= avctx->get_buffer(avctx, pic);
-
- if(r<0 || (s->linesize && (s->linesize != pic->linesize[0] || s->uvlinesize != pic->linesize[1]))){
- fprintf(stderr, "get_buffer() failed (stride changed), bye bye\n");
- return -1;
- }
-
- s->linesize = pic->linesize[0];
- s->uvlinesize= pic->linesize[1];
-
- if(pic->qscale_table==NULL)
- alloc_picture(s, (Picture*)pic);
+ alloc_picture(s, (Picture*)pic, 0);
s->current_picture= s->picture[i];
}
@@ -873,8 +928,6 @@ void MPV_frame_end(MpegEncContext *s)
s->last_pict_type = s->pict_type;
if(s->pict_type!=B_TYPE){
s->last_non_b_pict_type= s->pict_type;
- s->num_available_buffers++;
- if(s->num_available_buffers>2) s->num_available_buffers= 2;
}
s->current_picture.quality= s->qscale; //FIXME get average of qscale_table
@@ -892,7 +945,7 @@ void MPV_frame_end(MpegEncContext *s)
/* release non refernce frames */
for(i=0; i<MAX_PICTURE_COUNT; i++){
- if(s->picture[i].data[0] && !s->picture[i].reference)
+ if(s->picture[i].data[0] && !s->picture[i].reference /*&& s->picture[i].type!=FF_BUFFER_TYPE_SHARED*/)
s->avctx->release_buffer(s->avctx, (AVVideoFrame*)&s->picture[i]);
}
}
@@ -930,81 +983,81 @@ static int get_intra_count(MpegEncContext *s, uint8_t *src, uint8_t *ref, int st
return acc;
}
+
static int load_input_picture(MpegEncContext *s, AVVideoFrame *pic_arg){
AVVideoFrame *pic;
- int i,r;
+ int i;
const int encoding_delay= s->max_b_frames;
+ int direct=1;
- /* find unused Picture */
- for(i=0; i<MAX_PICTURE_COUNT; i++){
- if(s->picture[i].data[0]==NULL) break;
- }
- assert(i<MAX_PICTURE_COUNT);
-
- pic= (AVVideoFrame*)&s->picture[i];
- pic->reference= 1;
+ if(encoding_delay && !(s->flags&CODEC_FLAG_INPUT_PRESERVED)) direct=0;
+ if(pic_arg->linesize[0] != s->linesize) direct=0;
+ if(pic_arg->linesize[1] != s->uvlinesize) direct=0;
+ if(pic_arg->linesize[2] != s->uvlinesize) direct=0;
+
+// printf("%d %d %d %d\n",pic_arg->linesize[0], pic_arg->linesize[1], s->linesize, s->uvlinesize);
-// assert(avctx->get_buffer == default_get_buffer || avctx->get_buffer==NULL);
- r= s->avctx->get_buffer(s->avctx, pic);
+ if(direct){
+ i= find_unused_picture(s, 1);
- if(r<0 || (s->linesize && (s->linesize != pic->linesize[0] || s->uvlinesize != pic->linesize[1]))){
- fprintf(stderr, "get_buffer() failed (stride changed), bye bye\n");
- return -1;
- }
-
- assert(s->linesize==0 || s->linesize ==pic->linesize[0]);
- assert(s->uvlinesize==0 || s->uvlinesize==pic->linesize[1]);
- assert(pic->linesize[1] == pic->linesize[2]);
- s->linesize = pic->linesize[0];
- s->uvlinesize= pic->linesize[1];
+ pic= (AVVideoFrame*)&s->picture[i];
+ pic->reference= 1;
- if(pic->qscale_table==NULL)
- alloc_picture(s, (Picture*)pic);
+ for(i=0; i<4; i++){
+ pic->data[i]= pic_arg->data[i];
+ pic->linesize[i]= pic_arg->linesize[i];
+ }
+ alloc_picture(s, (Picture*)pic, 1);
+ }else{
+ i= find_unused_picture(s, 0);
-// assert(s->input_picture[0]==NULL || s->input_picture[0]->data[0]==NULL);
-
- if(s->input_picture[encoding_delay])
- pic->display_picture_number= s->input_picture[encoding_delay]->display_picture_number + 1;
-//printf("dpn2:%d\n", pic->display_picture_number);
+ pic= (AVVideoFrame*)&s->picture[i];
+ pic->reference= 1;
- /* shift buffer entries */
- for(i=1; i<MAX_PICTURE_COUNT /*s->encoding_delay+1*/; i++)
- s->input_picture[i-1]= s->input_picture[i];
-
- s->input_picture[encoding_delay]= (Picture*)pic;
- pic->pict_type= pic_arg->pict_type;
- pic->quality= pic_arg->quality;
-
- if( pic->data[0] == pic_arg->data[0]
- && pic->data[1] == pic_arg->data[1]
- && pic->data[2] == pic_arg->data[2]){
+ alloc_picture(s, (Picture*)pic, 0);
+
+ if( pic->data[0] == pic_arg->data[0]
+ && pic->data[1] == pic_arg->data[1]
+ && pic->data[2] == pic_arg->data[2]){
// empty
- }else{
- int h_chroma_shift, v_chroma_shift;
+ }else{
+ int h_chroma_shift, v_chroma_shift;
- avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift);
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift);
- for(i=0; i<3; i++){
- int src_stride= pic_arg->linesize[i];
- int dst_stride= i ? s->uvlinesize : s->linesize;
- int h_shift= i ? h_chroma_shift : 0;
- int v_shift= i ? v_chroma_shift : 0;
- int w= s->width >>h_shift;
- int h= s->height>>v_shift;
- uint8_t *src= pic_arg->data[i];
- uint8_t *dst= pic->data[i] + 16;
+ for(i=0; i<3; i++){
+ int src_stride= pic_arg->linesize[i];
+ int dst_stride= i ? s->uvlinesize : s->linesize;
+ int h_shift= i ? h_chroma_shift : 0;
+ int v_shift= i ? v_chroma_shift : 0;
+ int w= s->width >>h_shift;
+ int h= s->height>>v_shift;
+ uint8_t *src= pic_arg->data[i];
+ uint8_t *dst= pic->data[i];
- if(src_stride==dst_stride)
- memcpy(dst, src, src_stride*h);
- else{
- while(h--){
- memcpy(dst, src, w);
- dst += dst_stride;
- src += src_stride;
+ if(src_stride==dst_stride)
+ memcpy(dst, src, src_stride*h);
+ else{
+ while(h--){
+ memcpy(dst, src, w);
+ dst += dst_stride;
+ src += src_stride;
+ }
}
}
}
}
+ pic->quality= pic_arg->quality;
+ pic->pict_type= pic_arg->pict_type;
+
+ if(s->input_picture[encoding_delay])
+ pic->display_picture_number= s->input_picture[encoding_delay]->display_picture_number + 1;
+
+ /* shift buffer entries */
+ for(i=1; i<MAX_PICTURE_COUNT /*s->encoding_delay+1*/; i++)
+ s->input_picture[i-1]= s->input_picture[i];
+
+ s->input_picture[encoding_delay]= (Picture*)pic;
return 0;
}
@@ -1016,7 +1069,7 @@ static void select_input_picture(MpegEncContext *s){
if(s->reordered_input_picture[0])
coded_pic_num= s->reordered_input_picture[0]->coded_picture_number + 1;
-//printf("cpn:%d\n", coded_pic_num);
+
for(i=1; i<MAX_PICTURE_COUNT; i++)
s->reordered_input_picture[i-1]= s->reordered_input_picture[i];
s->reordered_input_picture[MAX_PICTURE_COUNT-1]= NULL;
@@ -1039,7 +1092,7 @@ static void select_input_picture(MpegEncContext *s){
if(i + 1 >= s->rc_context.num_entries) break;
}
}
-
+
if(s->input_picture[0]->pict_type){
/* user selected pict_type */
for(b_frames=0; b_frames<s->max_b_frames+1; b_frames++){
@@ -1056,8 +1109,8 @@ static void select_input_picture(MpegEncContext *s){
for(i=1; i<s->max_b_frames+1; i++){
if(s->input_picture[i]->b_frame_score==0){
s->input_picture[i]->b_frame_score=
- get_intra_count(s, s->input_picture[i ]->data[0] + 16,
- s->input_picture[i-1]->data[0] + 16, s->linesize) + 1;
+ get_intra_count(s, s->input_picture[i ]->data[0],
+ s->input_picture[i-1]->data[0], s->linesize) + 1;
}
}
for(i=0; i<s->max_b_frames; i++){
@@ -1097,14 +1150,38 @@ static void select_input_picture(MpegEncContext *s){
}
if(s->reordered_input_picture[0]){
- if(s->reordered_input_picture[0]->pict_type==B_TYPE){
- s->reordered_input_picture[0]->reference=0;
+ s->reordered_input_picture[0]->reference= s->reordered_input_picture[0]->pict_type!=B_TYPE;
+
+ if(s->reordered_input_picture[0]->type == FF_BUFFER_TYPE_SHARED){
+ int i= find_unused_picture(s, 0);
+ Picture *pic= &s->picture[i];
+
+ s->new_picture= *s->reordered_input_picture[0];
+
+ /* mark us unused / free shared pic */
+ for(i=0; i<4; i++)
+ s->reordered_input_picture[0]->data[i]= NULL;
+ s->reordered_input_picture[0]->type= 0;
+
+ pic->pict_type = s->reordered_input_picture[0]->pict_type;
+ pic->quality = s->reordered_input_picture[0]->quality;
+ pic->coded_picture_number = s->reordered_input_picture[0]->coded_picture_number;
+ pic->reference = s->reordered_input_picture[0]->reference;
+
+ alloc_picture(s, pic, 0);
+
+ s->current_picture= *pic;
+ }else{
+ assert( s->reordered_input_picture[0]->type==FF_BUFFER_TYPE_USER
+ || s->reordered_input_picture[0]->type==FF_BUFFER_TYPE_INTERNAL);
+
+ s->new_picture= *s->reordered_input_picture[0];
+
+ for(i=0; i<4; i++){
+ s->reordered_input_picture[0]->data[i]-=16; //FIXME dirty
+ }
+ s->current_picture= *s->reordered_input_picture[0];
}
- s->current_picture= *s->reordered_input_picture[0];
- s->new_picture= s->current_picture;
- s->new_picture.data[0]+=16;
- s->new_picture.data[1]+=16;
- s->new_picture.data[2]+=16;
s->picture_number= s->new_picture.display_picture_number;
//printf("dpn:%d\n", s->picture_number);
@@ -2231,7 +2308,7 @@ static int pix_diff_vcmp16x8(UINT8 *s1, UINT8*s2, int stride){ //FIXME move to d
void ff_draw_horiz_band(MpegEncContext *s){
if ( s->avctx->draw_horiz_band
- && (s->num_available_buffers>=1 || (!s->has_b_frames)) ) {
+ && (s->last_picture.data[0] || s->low_delay) ) {
UINT8 *src_ptr[3];
int y, h, offset;
y = s->mb_y * 16;
@@ -2244,7 +2321,7 @@ void ff_draw_horiz_band(MpegEncContext *s){
else
offset = y * s->linesize;
- if(s->pict_type==B_TYPE || (!s->has_b_frames)){
+ if(s->pict_type==B_TYPE || s->low_delay){
src_ptr[0] = s->current_picture.data[0] + offset;
src_ptr[1] = s->current_picture.data[1] + (offset >> 2);
src_ptr[2] = s->current_picture.data[2] + (offset >> 2);