summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/combined/ffmpeg/ff_video_decoder.c148
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];
- }
}
}
}