diff options
-rw-r--r-- | src/combined/ffmpeg/ff_video_decoder.c | 148 |
1 files changed, 110 insertions, 38 deletions
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index a1ad1cbde..60bb55f44 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -134,11 +134,41 @@ struct ff_video_decoder_s { 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); @@ -154,6 +184,8 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){ 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; @@ -168,7 +200,8 @@ static int get_buffer(AVCodecContext *context, AVFrame *av_frame){ 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")); @@ -557,6 +590,8 @@ static void ff_convert_frame(ff_video_decoder_t *this, vo_frame_t *img) { 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]; @@ -787,54 +822,91 @@ static void ff_convert_frame(ff_video_decoder_t *this, vo_frame_t *img) { } 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 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); - for (y = 0; y < this->bih.biHeight / 2; y++) { + if (this->full2mpeg) { - if (this->context->pix_fmt != PIX_FMT_YUV444P) { + uint8_t *ytab = this->ytab; + uint8_t *ctab = this->ctab; + uint8_t *p, *q; + int x; - xine_fast_memcpy (du, su, img->width/2); - xine_fast_memcpy (dv, sv, img->width/2); + 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]; + } - } else { + 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]; + } + } - int x; - uint8_t *src; - uint8_t *dst; + } else { - /* subsample */ + 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]; + } - 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 && this->context->pix_fmt != PIX_FMT_YUVJ420P) { - 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]; - } } } } |