shithub: treason

Download patch

ref: 325e635966381744f324b92c740a20c71dbae95c
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Tue Sep 8 09:49:42 EDT 2020

first version, playing AV1 ivf

--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,2 @@
+[a0125678vqki].out
+*.[o0125678vqki]
--- /dev/null
+++ b/LICENSE
@@ -1,0 +1,1 @@
+Public domain.
--- /dev/null
+++ b/README.md
@@ -1,0 +1,19 @@
+# treason
+
+A video player for 9front.
+
+## Status
+
+It can decode and play IVF AV1-encoded streams.  Only 8-bit per
+component YUV 4:2:0 is supported atm.
+
+More is coming soon.
+
+## Building
+
+	cd /tmp
+	git/clone https://git.sr.ht/~ft/dav1d
+	git/clone https://git.sr.ht/~ft/treason
+	cd dav1d/src && mk
+	cd ../../treason
+	mk install
--- /dev/null
+++ b/dec_av1.c
@@ -1,0 +1,148 @@
+#include <dav1d.h>
+#include "frame.h"
+#include "stream.h"
+#include "decoder.h"
+#include "misc.h"
+
+#pragma lib "../dav1d/src/libdav1d.$M.a"
+
+typedef struct Aux Aux;
+
+struct Aux {
+	Dav1dContext *c;
+};
+
+struct Stream {
+	Streamhdr;
+};
+
+static char *layout[] = {
+	[DAV1D_PIXEL_LAYOUT_I400] = "i400",
+    [DAV1D_PIXEL_LAYOUT_I420] = "i420",
+    [DAV1D_PIXEL_LAYOUT_I422] = "i422",
+    [DAV1D_PIXEL_LAYOUT_I444] = "i444",
+};
+
+static u8int *
+allocdata(void *data, int sz)
+{
+	return dav1d_data_create(data, sz);
+}
+
+static int
+readframe(Stream *s, Dav1dData *data)
+{
+	Streamframe f;
+
+	s->ops.aux = data;
+	if(Sread(s, &f) != 0)
+		return -1;
+	data->m.offset = f.offset;
+	data->m.timestamp = f.timestamp;
+
+	return 0;
+}
+
+static void
+decode(void *x)
+{
+	uvlong lasttimestamp;
+	Dav1dPicture pic;
+	Dav1dData data;
+	Decoder *d;
+	Frame *f;
+	Aux *a;
+	int res;
+
+	d = x;
+	a = d->aux;
+	lasttimestamp = 0;
+	memset(&pic, 0, sizeof(pic));
+	for(res = 0, data.sz = 0; data.sz > 0 || (res = readframe(d->s, &data)) == 0;){
+		if(nbrecvp(d->stop) != 0){
+			print("received stop\n");
+			break;
+		}
+
+		res = dav1d_get_picture(a->c, &pic);
+		if(res < 0){
+			if(res != DAV1D_ERR(EAGAIN)){
+				werrstr("dav1d_get_picture: %d", res);
+				break;
+			}
+		}else{
+			if((f = malloc(sizeof(*f) + pic.p.w*pic.p.h*3)) != nil){
+				f->w = pic.p.w;
+				f->h = pic.p.h;
+				yuv420_rgb24(f->w, f->h, pic.data[0], pic.data[1], pic.data[2], pic.stride[0], pic.stride[1], f->rgb, f->w*3);
+				f->dt = (pic.m.timestamp - lasttimestamp) * d->timebase * 1000000000ULL;
+				lasttimestamp = pic.m.timestamp;
+				dav1d_picture_unref(&pic);
+
+				if(sendp(d->frames, f) < 0){
+					free(f);
+					break;
+				}
+			}
+		}
+
+		res = dav1d_send_data(a->c, &data);
+		if(res < 0){
+			if(res != DAV1D_ERR(EAGAIN)){
+				werrstr("dav1d_send_data: %d", res);
+				break;
+			}
+		}
+	}
+	if(res != 0)
+		fprint(2, "av1: %r\n");
+
+	if(data.sz > 0)
+		dav1d_data_unref(&data);
+
+	/* drain */
+	while(dav1d_get_picture(a->c, &pic) >= 0)
+		dav1d_picture_unref(&pic);
+
+	dav1d_close(&a->c);
+	sendp(d->finished, nil);
+	free(a);
+
+	threadexits(nil);
+}
+
+static int
+av1open(Decoder *d)
+{
+	Dav1dSettings av1s;
+	Aux *a;
+	int res;
+
+	a = calloc(1, sizeof(*a));
+
+	dav1d_default_settings(&av1s);
+	av1s.n_frame_threads = nproc;
+	av1s.n_tile_threads = nproc;
+
+	if((res = dav1d_open(&a->c, &av1s)) != 0){
+		werrstr("dav1d_open: %d", res);
+		free(a);
+		return -1;
+	}
+	proccreate(decode, d, 16384);
+	d->aux = a;
+	d->s->ops.alloc = allocdata;
+
+	return 0;
+}
+
+static void
+av1close(Decoder *d)
+{
+	USED(d);
+}
+
+Decoderops av1ops = {
+	.open = av1open,
+	.close = av1close,
+};
--- /dev/null
+++ b/decoder.c
@@ -1,0 +1,62 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "stream.h"
+#include "decoder.h"
+#include "frame.h"
+
+extern Decoderops av1ops;
+
+static struct {
+	char *name;
+	Decoderops *o;
+	int fmt;
+}ops[] = {
+	{"AV1", &av1ops, FmtAV1},
+};
+
+Decoder *
+Dopen(Stream *s, Streaminfo *info)
+{
+	Decoder *d;
+	int i;
+
+	if((d = calloc(1, sizeof(*d))) == nil)
+		return nil;
+
+	d->timebase = (double)info->timebase.num/(double)info->timebase.denum;
+	d->s = s;
+	d->frames = chancreate(sizeof(Frame*), 4);
+	d->finished = chancreate(sizeof(void*), 1);
+	d->stop = chancreate(sizeof(void*), 1);
+	memmove(&d->info, info, sizeof(info));
+
+	for(i = 0; i < nelem(ops); i++){
+		if(ops[i].fmt == info->fmt){
+			if(ops[i].o->open(d) < 0){
+				werrstr("%s: %r", ops[i].name);
+				goto err;
+			}
+			d->ops = ops[i].o;
+			break;
+		}
+	}
+
+	assert(i < nelem(ops));
+
+	return d;
+err:
+	return nil;
+}
+
+void
+Dclose(Decoder *d)
+{
+	d->ops->close(d);
+	chanclose(d->frames);
+	sendp(d->stop, nil);
+	recvp(d->finished);
+	chanclose(d->stop);
+	chanclose(d->finished);
+	free(d);
+}
--- /dev/null
+++ b/decoder.h
@@ -1,0 +1,22 @@
+typedef struct Decoder Decoder;
+typedef struct Decoderops Decoderops;
+
+struct Decoder {
+	Stream *s;
+	Channel *frames;
+	Channel *finished;
+	Channel *stop;
+	Streaminfo info;
+	Decoderops *ops;
+	double timebase;
+
+	void *aux;
+};
+
+struct Decoderops {
+	int (*open)(Decoder *d);
+	void (*close)(Decoder *d);
+};
+
+Decoder *Dopen(Stream *s, Streaminfo *info);
+void Dclose(Decoder *d);
--- /dev/null
+++ b/frame.h
@@ -1,0 +1,7 @@
+typedef struct Frame Frame;
+
+struct Frame {
+	int w, h;
+	uvlong dt;
+	u8int rgb[1];
+};
--- /dev/null
+++ b/ivf.c
@@ -1,0 +1,157 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "stream.h"
+
+struct Stream {
+	Streamhdr;
+	Biobuf *b;
+	u8int *buf;
+	int bufsz;
+};
+
+static int
+Bu16le(Biobuf *b, u16int *o)
+{
+	int x;
+
+	x = Bgetc(b);
+	x |= Bgetc(b)<<8;
+	*o = x;
+	if(x < 0)
+		werrstr("failed to read 2 bytes");
+
+	return x < 0 ? -1 : 0;
+}
+
+static int
+Bu32le(Biobuf *b, u32int *o)
+{
+	int x, i;
+
+	*o = 0;
+	for(i = 0; i < 4; *o |= x<<(i*8), i++){
+		if((x = Bgetc(b)) < 0){
+			werrstr("failed to read 4 bytes");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+Bu64le(Biobuf *b, u64int *o)
+{
+	int x, i;
+
+	*o = 0;
+	for(i = 0; i < 8; *o |= x<<(i*8), i++){
+		if((x = Bgetc(b)) < 0){
+			werrstr("failed to read 8 bytes");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static Stream *
+ivfopen(char *filename, Streaminfo *info, int *failed)
+{
+	Biobuf *b;
+	Stream *s;
+	u16int hlen, w, h;
+	u32int tbdenum, tbnum;
+	char tmp[6];
+
+	if((b = Bopen(filename, OREAD)) == nil)
+		return nil;
+	if(Bread(b, tmp, 6) != 6 || memcmp(tmp, "DKIF", 4) != 0 || Bu16le(b, &hlen) < 0){
+		Bterm(b);
+		return nil;
+	}
+
+	if((s = calloc(1, sizeof(*s))) == nil)
+		goto err;
+	if(hlen < 0x20 || Bread(b, tmp, 4) != 4){
+		werrstr("invalid header: hlen=%d", hlen);
+		goto err;
+	}
+	if(memcmp(tmp, "AV01", 4) != 0){ /* nothing else is supported yet */
+		werrstr("unsupported format %.*s", 4, tmp);
+		goto err;
+	}
+	info->fmt = FmtAV1;
+	if(Bu16le(b, &w) < 0 || Bu16le(b, &h) < 0 || Bu32le(b, &tbdenum) < 0 || Bu32le(b, &tbnum) < 0){
+		werrstr("invalid header: %r");
+		goto err;
+	}
+	info->w = w;
+	info->h = h;
+	info->timebase.denum = tbdenum;
+	info->timebase.num = tbnum;
+	if(Bseek(b, hlen, 0) != hlen){
+		werrstr("invalid IVF stream");
+		goto err;
+	}
+	s->b = b;
+
+	return s;
+err:
+	*failed = 1;
+	Bterm(b);
+	free(s);
+	return nil;
+}
+
+static void
+ivfclose(Stream *s)
+{
+	Bterm(s->b);
+	free(s->buf);
+	free(s);
+}
+
+static int
+ivfread(Stream *s, Streamframe *f)
+{
+	u64int timestamp;
+	u32int sz;
+	u8int *buf;
+
+	f->offset = Boffset(s->b);
+	if(Bu32le(s->b, &sz) < 0 || Bu64le(s->b, &timestamp) || (int)sz < 0)
+		return -1;
+	buf = s->buf;
+	if(s->ops.alloc != nil)
+		buf = s->ops.alloc(s->ops.aux, sz);
+	else if(sz > s->bufsz){
+		if((buf = realloc(s->buf, sz)) == nil){
+			werrstr("frame is too big: %d bytes", sz);
+			return -1;
+		}
+		s->buf = buf;
+	}
+	if(Bread(s->b, buf, sz) != sz){
+		werrstr("short read");
+		return -1;
+	}
+	f->buf = buf;
+	f->sz = sz;
+	f->timestamp = timestamp;
+
+	return 0;
+}
+
+static vlong
+ivfoffset(Stream *s)
+{
+	return Boffset(s->b);
+}
+
+Streamops ivfops = {
+	.open = ivfopen,
+	.close = ivfclose,
+	.read = ivfread,
+};
--- /dev/null
+++ b/main.c
@@ -1,0 +1,170 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <thread.h>
+#include "frame.h"
+#include "misc.h"
+#include "stream.h"
+#include "decoder.h"
+
+int mainstacksize = 128*1024;
+
+static Image *curim;
+static uvlong lastframe;
+
+static void
+drawframe(Frame *f)
+{
+	uvlong x, end, left;
+	static uvlong delay;
+	Rectangle r;
+
+	lockdisplay(display);
+
+	if(curim != nil && (Dx(curim->r) != f->w || Dy(curim->r) != f->h)){
+		freeimage(curim);
+		curim = nil;
+	}
+	r = Rect(0,0,f->w,f->h);
+	if(curim == nil)
+		curim = allocimage(display, r, RGB24, 0, DNofill);
+	loadimage(curim, r, f->rgb, f->w*f->h*3);
+
+	if(lastframe == 0)
+		lastframe = nanosec();
+
+	end = lastframe + f->dt - delay;
+	while(1){
+		x = nanosec();
+		if(x >= end)
+			break;
+		left = end - x;
+		if(left > 750000000ULL)
+			sleep(70);
+		else if(left > 250000000ULL)
+			sleep(20);
+		else if(left > 100000000ULL)
+			sleep(1);
+	}
+
+	x = nanosec();
+	if(Dx(r) < Dx(screen->r) && Dy(r) < Dy(screen->r))
+		r = rectsubpt(screen->r, divpt(Pt(Dx(r)-Dx(screen->r), Dy(r)-Dy(screen->r)), 2));
+	else
+		r = screen->r;
+	draw(screen, r, curim, nil, ZP);
+	flushimage(display, 1);
+	unlockdisplay(display);
+
+	delay = nanosec() - x;
+	lastframe += f->dt;
+
+	free(f);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	enum {
+		Cframe,
+		Cplayerdone,
+		Cmouse,
+		Ckeyboard,
+		Cresize,
+		Cnum,
+	};
+	Frame *frame;
+	Mousectl *mctl;
+	Keyboardctl *kctl;
+	Rune key;
+	Mouse m;
+	char *s;
+	Stream *stream;
+	Streaminfo info;
+	Decoder *d;
+	int i, end, done, res;
+	Alt a[Cnum+1] =
+	{
+		[Cframe] = { nil, &frame, CHANRCV },
+		[Cplayerdone] = { nil, nil, CHANRCV },
+		[Cmouse] = { nil, &m, CHANRCV },
+		[Ckeyboard] = { nil, &key, CHANRCV },
+		[Cresize] =  { nil, nil, CHANRCV },
+		[Cnum] = { nil, nil, CHANEND },
+	};
+
+	ARGBEGIN{
+	}ARGEND
+
+	if(argc < 1)
+		sysfatal("usage");
+
+	nproc = atoi((s = getenv("NPROC")) != nil ? s : "1");
+
+	srand(nanosec());
+	if(initdraw(nil, nil, "treason") < 0)
+		sysfatal("initdraw: %r");
+	flushimage(display, 1);
+	display->locking = 1;
+	unlockdisplay(display);
+	if((mctl = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	if((kctl = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+
+	a[Cmouse].c = mctl->c;
+	a[Cresize].c = mctl->resizec;
+	a[Ckeyboard].c = kctl->c;
+
+	for(end = i = 0; !end && i < argc; i++){
+		draw(screen, screen->r, display->black, nil, ZP);
+		if((stream = Sopen(argv[i], &info)) == nil)
+			sysfatal("%r");
+		if((d = Dopen(stream, &info)) == nil)
+			sysfatal("%r");
+
+		a[Cframe].c = d->frames;
+		a[Cplayerdone].c = d->finished;
+		lastframe = 0;
+
+		for(done = 0; !done && !end;){
+			res = alt(a);
+			switch(res){
+			case Cframe:
+				drawframe(frame);
+				break;
+
+			case Cplayerdone:
+				done = 1;
+				break;
+
+			case Cmouse:
+				break;
+
+			case Ckeyboard:
+				end = key == 'q' || key == Kdel;
+				done = key == '\n';
+				break;
+
+			case Cresize:
+				lockdisplay(display);
+				if(getwindow(display, Refnone) < 0)
+					sysfatal("getwindow: %r");
+				freeimage(curim);
+				curim = nil;
+				draw(screen, screen->r, display->black, nil, ZP);
+				flushimage(display, 1);
+				unlockdisplay(display);
+				break;
+			}
+		}
+
+		Dclose(d);
+		Sclose(stream);
+	}
+
+	threadexitsall(nil);
+}
--- /dev/null
+++ b/misc.c
@@ -1,0 +1,34 @@
+#include <u.h>
+#include <libc.h>
+#include <tos.h>
+
+int nproc;
+
+uvlong
+nanosec(void)
+{
+	static uvlong fasthz, xstart;
+	uvlong x, div;
+
+	if(fasthz == ~0ULL)
+		return nsec() - xstart;
+
+	if(fasthz == 0){
+		if((fasthz = _tos->cyclefreq) == 0){
+			fasthz = ~0ULL;
+			xstart = nsec();
+			fprint(2, "cyclefreq not available, falling back to nsec()\n");
+			fprint(2, "you might want to disable aux/timesync\n");
+			return 0;
+		}else{
+			cycles(&xstart);
+		}
+	}
+	cycles(&x);
+	x -= xstart;
+
+	/* this is ugly */
+	for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL);
+
+	return x / (fasthz / div);
+}
--- /dev/null
+++ b/misc.h
@@ -1,0 +1,7 @@
+uvlong nanosec(void);
+void yuv420_rgb24(
+	u32int width, u32int height,
+	const u8int *Y, const u8int *U, const u8int *V, u32int Y_stride, u32int UV_stride,
+	u8int *RGB, u32int RGB_stride);
+
+extern int nproc;
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,27 @@
+</$objtype/mkfile
+
+TARG=treason
+CFLAGS=$CFLAGS -p -I../dav1d/include/dav1d -I../dav1d/src/plan9
+BIN=/$objtype/bin
+MAN=/sys/man/1
+
+HFILES=\
+	decoder.h\
+	frame.h\
+	misc.h\
+	stream.h\
+
+OFILES=\
+	dec_av1.$O\
+	decoder.$O\
+	ivf.$O\
+	main.$O\
+	misc.$O\
+	stream.$O\
+	yuv.$O\
+
+default:V:	all
+
+</sys/src/cmd/mkone
+
+install:V: $MAN/$TARG
--- /dev/null
+++ b/stream.c
@@ -1,0 +1,57 @@
+#include <u.h>
+#include <libc.h>
+#include "stream.h"
+
+struct Stream {
+	Streamops ops;
+};
+
+extern Streamops ivfops;
+
+static struct {
+	char *name;
+	Streamops *o;
+}ops[] = {
+	{"ivf", &ivfops},
+};
+
+Stream *
+Sopen(char *filename, Streaminfo *info)
+{
+	int i, failed;
+	Stream *s;
+
+	for(i = 0; i < nelem(ops); i++){
+		failed = 0;
+		if((s = ops[i].o->open(filename, info, &failed)) != nil){
+			memmove(&s->ops, ops[i].o, sizeof(Streamops));
+			return s;
+		}
+		if(failed){
+			werrstr("%s: %r", ops[i].name);
+			return nil;
+		}
+	}
+
+	werrstr("unknown format");
+
+	return nil;
+}
+
+void
+Sclose(Stream *s)
+{
+	s->ops.close(s);
+}
+
+int
+Sread(Stream *s, Streamframe *f)
+{
+	return s->ops.read(s, f);
+}
+
+vlong
+Soffset(Stream *s)
+{
+	return s->ops.offset(s);
+}
--- /dev/null
+++ b/stream.h
@@ -1,0 +1,45 @@
+typedef struct Stream Stream;
+typedef struct Streamhdr Streamhdr;
+typedef struct Streamframe Streamframe;
+typedef struct Streaminfo Streaminfo;
+typedef struct Streamops Streamops;
+#pragma incomplete Stream
+
+enum {
+	FmtAV1,
+};
+
+struct Streamframe {
+	u8int *buf;
+	int sz;
+	uvlong offset;
+	uvlong timestamp;
+};
+
+struct Streamops {
+	Stream *(*open)(char *filename, Streaminfo *info, int *failed);
+	u8int *(*alloc)(void *aux, int sz);
+	void (*close)(Stream *s);
+	vlong (*offset)(Stream *s);
+	int (*read)(Stream *s, Streamframe *f);
+
+	void *aux;
+};
+
+struct Streamhdr {
+	Streamops ops;
+};
+
+struct Streaminfo {
+	struct {
+		uvlong denum, num;
+	}timebase;
+	int fmt;
+	int w;
+	int h;
+};
+
+Stream *Sopen(char *filename, Streaminfo *info);
+vlong Soffset(Stream *s);
+void Sclose(Stream *s);
+int Sread(Stream *s, Streamframe *f);
--- /dev/null
+++ b/yuv.c
@@ -1,0 +1,93 @@
+#include <u.h>
+
+/* yuv→rgb by Adrien Descamps */
+
+#define clamp(v) ((v)<0?0 : ((v)>255?255:v))
+#define FIXED_POINT_VALUE(value, precision) ((int)(((value)*(1<<precision))+0.5))
+
+typedef struct
+{
+	u8int cb_factor;   // [(255*CbNorm)/CbRange]
+	u8int cr_factor;   // [(255*CrNorm)/CrRange]
+	u8int g_cb_factor; // [Bf/Gf*(255*CbNorm)/CbRange]
+	u8int g_cr_factor; // [Rf/Gf*(255*CrNorm)/CrRange]
+	u8int y_factor;    // [(YMax-YMin)/255]
+	u8int y_offset;    // YMin
+} YUV2RGBParam;
+
+#define YUV2RGB_PARAM(Rf, Bf, YMin, YMax, CbCrRange) \
+	{.cb_factor=FIXED_POINT_VALUE(255.0*(2.0*(1-Bf))/CbCrRange, 6), \
+	.cr_factor=FIXED_POINT_VALUE(255.0*(2.0*(1-Rf))/CbCrRange, 6), \
+	.g_cb_factor=FIXED_POINT_VALUE(Bf/(1.0-Bf-Rf)*255.0*(2.0*(1-Bf))/CbCrRange, 7), \
+	.g_cr_factor=FIXED_POINT_VALUE(Rf/(1.0-Bf-Rf)*255.0*(2.0*(1-Rf))/CbCrRange, 7), \
+	.y_factor=FIXED_POINT_VALUE(255.0/(YMax-YMin), 7), \
+	.y_offset=YMin}
+
+static const YUV2RGBParam YUV2RGB[3] = {
+	// ITU-T T.871 (JPEG)
+	YUV2RGB_PARAM(0.299, 0.114, 0.0, 255.0, 255.0),
+	// ITU-R BT.601-7
+	YUV2RGB_PARAM(0.299, 0.114, 16.0, 235.0, 224.0),
+	// ITU-R BT.709-6
+	YUV2RGB_PARAM(0.2126, 0.0722, 16.0, 235.0, 224.0)
+};
+
+void yuv420_rgb24(
+	u32int width, u32int height,
+	const u8int *Y, const u8int *U, const u8int *V, u32int Y_stride, u32int UV_stride,
+	u8int *RGB, u32int RGB_stride)
+{
+	const YUV2RGBParam *const param = &(YUV2RGB[0]);
+	u32int x, y;
+	for(y=0; y<(height-1); y+=2)
+	{
+		const u8int *y_ptr1=Y+y*Y_stride,
+			*y_ptr2=Y+(y+1)*Y_stride,
+			*u_ptr=U+(y/2)*UV_stride,
+			*v_ptr=V+(y/2)*UV_stride;
+
+		u8int *rgb_ptr1=RGB+y*RGB_stride,
+			*rgb_ptr2=RGB+(y+1)*RGB_stride;
+
+		for(x=0; x<(width-1); x+=2)
+		{
+			s8int u_tmp, v_tmp;
+			u_tmp = u_ptr[0]-128;
+			v_tmp = v_ptr[0]-128;
+
+			//compute Cb Cr color offsets, common to four pixels
+			s16int b_cb_offset, r_cr_offset, g_cbcr_offset;
+			b_cb_offset = (param->cb_factor*u_tmp)>>6;
+			r_cr_offset = (param->cr_factor*v_tmp)>>6;
+			g_cbcr_offset = (param->g_cb_factor*u_tmp + param->g_cr_factor*v_tmp)>>7;
+
+			s16int y_tmp;
+			y_tmp = (param->y_factor*(y_ptr1[0]-param->y_offset))>>7;
+			rgb_ptr1[2] = clamp(y_tmp + r_cr_offset);
+			rgb_ptr1[1] = clamp(y_tmp - g_cbcr_offset);
+			rgb_ptr1[0] = clamp(y_tmp + b_cb_offset);
+
+			y_tmp = (param->y_factor*(y_ptr1[1]-param->y_offset))>>7;
+			rgb_ptr1[5] = clamp(y_tmp + r_cr_offset);
+			rgb_ptr1[4] = clamp(y_tmp - g_cbcr_offset);
+			rgb_ptr1[3] = clamp(y_tmp + b_cb_offset);
+
+			y_tmp = (param->y_factor*(y_ptr2[0]-param->y_offset))>>7;
+			rgb_ptr2[2] = clamp(y_tmp + r_cr_offset);
+			rgb_ptr2[1] = clamp(y_tmp - g_cbcr_offset);
+			rgb_ptr2[0] = clamp(y_tmp + b_cb_offset);
+
+			y_tmp = (param->y_factor*(y_ptr2[1]-param->y_offset))>>7;
+			rgb_ptr2[5] = clamp(y_tmp + r_cr_offset);
+			rgb_ptr2[4] = clamp(y_tmp - g_cbcr_offset);
+			rgb_ptr2[3] = clamp(y_tmp + b_cb_offset);
+
+			rgb_ptr1 += 6;
+			rgb_ptr2 += 6;
+			y_ptr1 += 2;
+			y_ptr2 += 2;
+			u_ptr += 1;
+			v_ptr += 1;
+		}
+	}
+}