diff -uNr xine-lib-1.2.1.orig/src/combined/ffmpeg/ffmpeg_compat.h xine-lib-1.2.1/src/combined/ffmpeg/ffmpeg_compat.h --- xine-lib-1.2.1.orig/src/combined/ffmpeg/ffmpeg_compat.h 2012-02-04 01:41:43.000000000 +0100 +++ xine-lib-1.2.1/src/combined/ffmpeg/ffmpeg_compat.h 2012-02-09 21:00:25.000000000 +0100 @@ -91,5 +91,9 @@ # define AVAUDIO 2 #endif +/* AVFrame.age */ +#if !(LIBAVCODEC_VERSION_MAJOR >= 53 && LIBAVCODEC_VERSION_MAJOR >= 28 && LIBAVCODEC_VERSION_MICRO >= 1) +# define AVFRAMEAGE 1 +#endif #endif /* XINE_AVCODEC_COMPAT_H */ diff -uNr xine-lib-1.2.1.orig/src/combined/ffmpeg/ff_video_decoder.c xine-lib-1.2.1/src/combined/ffmpeg/ff_video_decoder.c --- xine-lib-1.2.1.orig/src/combined/ffmpeg/ff_video_decoder.c 2012-02-04 01:41:43.000000000 +0100 +++ xine-lib-1.2.1/src/combined/ffmpeg/ff_video_decoder.c 2012-05-10 21:50:50.000000000 +0200 @@ -68,6 +68,7 @@ int thread_count; int8_t skip_loop_filter_enum; int8_t choose_speed_over_accuracy; + uint8_t enable_dri; xine_t *xine; } ff_video_class_t; @@ -92,7 +93,7 @@ uint8_t is_mpeg12:1; uint8_t pp_available:1; uint8_t yuv_init:1; - uint8_t is_direct_rendering_disabled:1; + uint8_t is_direct_rendering_disabled:1; /* used only to avoid flooding log */ uint8_t cs_convert_init:1; uint8_t assume_bad_field_picture:1; @@ -127,13 +128,45 @@ yuv_planes_t yuv; +#ifdef AVPaletteControl AVPaletteControl palette_control; +#endif + + int color_matrix, full2mpeg; + unsigned char ytab[256], ctab[256]; #ifdef LOG enum PixelFormat debug_fmt; #endif }; +static void ff_check_colorspace (ff_video_decoder_t *this) { + int i, cm; + + cm = this->context->colorspace << 1; + /* ffmpeg bug: color_range not set by svq3 decoder */ + i = this->context->pix_fmt; + if (cm && ((i == PIX_FMT_YUVJ420P) || (i == PIX_FMT_YUVJ444P) || + (this->context->color_range == AVCOL_RANGE_JPEG))) + cm |= 1; + + /* report changes of colorspyce and/or color range */ + if (cm != this->color_matrix) { + this->color_matrix = cm; + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "ffmpeg_video_dec: color matrix #%d\n", cm >> 1); + + this->full2mpeg = 0; + if (cm & 1) { + /* sigh. fall back to manual conversion */ + this->full2mpeg = 1; + for (i = 0; i < 256; i++) { + this->ytab[i] = (219 * i + 127) / 255 + 16; + this->ctab[i] = 112 * (i - 128) / 127 + 128; + } + } + } +} static void set_stream_info(ff_video_decoder_t *this) { _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->bih.biWidth); @@ -149,6 +182,8 @@ int width = context->width; int height = context->height; + ff_check_colorspace (this); + if (!this->bih.biWidth || !this->bih.biHeight) { this->bih.biWidth = width; this->bih.biHeight = height; @@ -163,7 +198,8 @@ avcodec_align_dimensions(context, &width, &height); - if( this->context->pix_fmt != PIX_FMT_YUV420P && this->context->pix_fmt != PIX_FMT_YUVJ420P ) { + if (this->full2mpeg || (this->context->pix_fmt != PIX_FMT_YUV420P && + this->context->pix_fmt != PIX_FMT_YUVJ420P)) { if (!this->is_direct_rendering_disabled) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_video_dec: unsupported frame format, DR1 disabled.\n")); @@ -195,6 +231,8 @@ } } + this->is_direct_rendering_disabled = 0; + img = this->stream->video_out->get_frame (this->stream->video_out, width, height, @@ -215,7 +253,9 @@ /* We should really keep track of the ages of xine frames (see * avcodec_default_get_buffer in libavcodec/utils.c) * For the moment tell ffmpeg that every frame is new (age = bignumber) */ +#ifdef AVFRAMEAGE av_frame->age = 256*256*256*64; +#endif av_frame->type= FF_BUFFER_TYPE_USER; @@ -309,7 +349,7 @@ /* Some codecs (eg rv10) copy flags in init so it's necessary to set * this flag here in case we are going to use direct rendering */ - if(this->codec->capabilities & CODEC_CAP_DR1 && this->codec->id != CODEC_ID_H264) { + if(this->codec->capabilities & CODEC_CAP_DR1 && this->class->enable_dri) { this->context->flags |= CODEC_FLAG_EMU_EDGE; } @@ -320,6 +360,13 @@ if (this->class->choose_speed_over_accuracy) this->context->flags2 |= CODEC_FLAG2_FAST; +#ifdef DEPRECATED_AVCODEC_THREAD_INIT + if (this->class->thread_count > 1) { + if (this->codec->id != CODEC_ID_SVQ3) + this->context->thread_count = this->class->thread_count; + } +#endif + pthread_mutex_lock(&ffmpeg_lock); if (avcodec_open (this->context, this->codec) < 0) { pthread_mutex_unlock(&ffmpeg_lock); @@ -347,14 +394,13 @@ } } +#ifndef DEPRECATED_AVCODEC_THREAD_INIT if (this->class->thread_count > 1) { if (this->codec->id != CODEC_ID_SVQ3 -#ifndef DEPRECATED_AVCODEC_THREAD_INIT - && avcodec_thread_init(this->context, this->class->thread_count) != -1 -#endif - ) + && avcodec_thread_init(this->context, this->class->thread_count) != -1) this->context->thread_count = this->class->thread_count; } +#endif this->context->skip_loop_filter = skip_loop_filter_enum_values[this->class->skip_loop_filter_enum]; @@ -383,7 +429,7 @@ /* enable direct rendering by default */ this->output_format = XINE_IMGFMT_YV12; #ifdef ENABLE_DIRECT_RENDERING - if( this->codec->capabilities & CODEC_CAP_DR1 && this->codec->id != CODEC_ID_H264 ) { + if( this->codec->capabilities & CODEC_CAP_DR1 && this->class->enable_dri ) { this->context->get_buffer = get_buffer; this->context->release_buffer = release_buffer; xprintf(this->stream->xine, XINE_VERBOSITY_LOG, @@ -442,6 +488,12 @@ class->pp_quality = entry->num_value; } +static void dri_cb(void *user_data, xine_cfg_entry_t *entry) { + ff_video_class_t *class = (ff_video_class_t *) user_data; + + class->enable_dri = entry->num_value; +} + static void pp_change_quality (ff_video_decoder_t *this) { this->pp_quality = this->class->pp_quality; @@ -542,6 +594,8 @@ printf ("frame format == %08x\n", this->debug_fmt = this->context->pix_fmt); #endif + ff_check_colorspace (this); + dy = img->base[0]; du = img->base[1]; dv = img->base[2]; @@ -772,54 +826,91 @@ } else { - for (y = 0; y < this->bih.biHeight; y++) { - xine_fast_memcpy (dy, sy, img->width); - - dy += img->pitches[0]; - - sy += this->av_frame->linesize[0]; - } - - for (y = 0; y < this->bih.biHeight / 2; y++) { + int subsamph = (this->context->pix_fmt == PIX_FMT_YUV444P) + || (this->context->pix_fmt == PIX_FMT_YUVJ444P); + int subsampv = (this->context->pix_fmt != PIX_FMT_YUV420P) + && (this->context->pix_fmt != PIX_FMT_YUVJ420P); + + if (this->full2mpeg) { + + uint8_t *ytab = this->ytab; + uint8_t *ctab = this->ctab; + uint8_t *p, *q; + int x; + + for (y = 0; y < this->bih.biHeight; y++) { + p = sy; + q = dy; + for (x = img->width; x > 0; x--) *q++ = ytab[*p++]; + dy += img->pitches[0]; + sy += this->av_frame->linesize[0]; + } - if (this->context->pix_fmt != PIX_FMT_YUV444P) { + for (y = 0; y < this->bih.biHeight / 2; y++) { + if (!subsamph) { + p = su, q = du; + for (x = img->width / 2; x > 0; x--) *q++ = ctab[*p++]; + p = sv, q = dv; + for (x = img->width / 2; x > 0; x--) *q++ = ctab[*p++]; + } else { + p = su, q = sv; + for (x = img->width / 2; x > 0; x--) {*q++ = ctab[*p]; p += 2;} + p = sv, q = dv; + for (x = img->width / 2; x > 0; x--) {*q++ = ctab[*p]; p += 2;} + } + du += img->pitches[1]; + dv += img->pitches[2]; + if (subsampv) { + su += 2 * this->av_frame->linesize[1]; + sv += 2 * this->av_frame->linesize[2]; + } else { + su += this->av_frame->linesize[1]; + sv += this->av_frame->linesize[2]; + } + } - xine_fast_memcpy (du, su, img->width/2); - xine_fast_memcpy (dv, sv, img->width/2); + } else { - } else { + for (y = 0; y < this->bih.biHeight; y++) { + xine_fast_memcpy (dy, sy, img->width); + dy += img->pitches[0]; + sy += this->av_frame->linesize[0]; + } - int x; - uint8_t *src; - uint8_t *dst; - - /* subsample */ - - src = su; dst = du; - for (x=0; x<(img->width/2); x++) { - *dst = *src; - dst++; - src += 2; + for (y = 0; y < this->bih.biHeight / 2; y++) { + if (!subsamph) { + xine_fast_memcpy (du, su, img->width/2); + xine_fast_memcpy (dv, sv, img->width/2); + } else { + int x; + uint8_t *src; + uint8_t *dst; + src = su; + dst = du; + for (x = 0; x < (img->width / 2); x++) { + *dst = *src; + dst++; + src += 2; + } + src = sv; + dst = dv; + for (x = 0; x < (img->width / 2); x++) { + *dst = *src; + dst++; + src += 2; + } } - src = sv; dst = dv; - for (x=0; x<(img->width/2); x++) { - *dst = *src; - dst++; - src += 2; + du += img->pitches[1]; + dv += img->pitches[2]; + if (subsampv) { + su += 2*this->av_frame->linesize[1]; + sv += 2*this->av_frame->linesize[2]; + } else { + su += this->av_frame->linesize[1]; + sv += this->av_frame->linesize[2]; } - } - du += img->pitches[1]; - dv += img->pitches[2]; - - if (this->context->pix_fmt != PIX_FMT_YUV420P) { - su += 2*this->av_frame->linesize[1]; - sv += 2*this->av_frame->linesize[2]; - } else { - su += this->av_frame->linesize[1]; - sv += this->av_frame->linesize[2]; - } } } } @@ -1023,7 +1114,9 @@ memcpy(this->context->extradata, buf->decoder_info_ptr[2], buf->decoder_info[2]); - } else if (buf->decoder_info[1] == BUF_SPECIAL_PALETTE) { + } +#ifdef AVPaletteControl + else if (buf->decoder_info[1] == BUF_SPECIAL_PALETTE) { unsigned int i; palette_entry_t *demuxer_palette; @@ -1042,7 +1135,9 @@ } decoder_palette->palette_changed = 1; - } else if (buf->decoder_info[1] == BUF_SPECIAL_RV_CHUNK_TABLE) { + } +#endif + else if (buf->decoder_info[1] == BUF_SPECIAL_RV_CHUNK_TABLE) { int i; lprintf("BUF_SPECIAL_RV_CHUNK_TABLE\n"); @@ -1504,8 +1599,8 @@ img->duration = video_step_to_use; /* additionally crop away the extra pixels due to adjusting frame size above */ - img->crop_right = this->crop_right + (img->width - this->bih.biWidth); - img->crop_bottom = this->crop_bottom + (img->height - this->bih.biHeight); + img->crop_right = img->width - this->bih.biWidth; + img->crop_bottom = img->height - this->bih.biHeight; /* transfer some more frame settings for deinterlacing */ img->progressive_frame = !this->av_frame->interlaced_frame; @@ -1536,8 +1631,8 @@ img->duration = video_step_to_use; /* additionally crop away the extra pixels due to adjusting frame size above */ - img->crop_right = ((this->bih.biWidth <= 0) ? 0 : this->crop_right) + (img->width - this->bih.biWidth); - img->crop_bottom = ((this->bih.biHeight <= 0) ? 0 : this->crop_bottom) + (img->height - this->bih.biHeight); + img->crop_right = this->bih.biWidth <= 0 ? 0 : (img->width - this->bih.biWidth); + img->crop_bottom = this->bih.biHeight <= 0 ? 0 : (img->height - this->bih.biHeight); img->bad_frame = 1; this->skipframes = img->draw(img, this->stream); @@ -1758,7 +1853,9 @@ this->av_frame = avcodec_alloc_frame(); this->context = avcodec_alloc_context(); this->context->opaque = this; +#ifdef AVPaletteControl this->context->palctrl = NULL; +#endif this->decoder_ok = 0; this->decoder_init_mode = 1; @@ -1839,6 +1936,12 @@ "A change of this setting will take effect with playing the next stream."), 10, choose_speed_over_accuracy_cb, this); + this->enable_dri = xine->config->register_bool(config, "video.processing.ffmpeg_direct_rendering", 1, + _("Enable direct rendering"), + _("Disable direct rendering if you are experiencing lock-ups with\n" + "streams with lot of reference frames."), + 10, dri_cb, this); + return this; }