Skip to content
Permalink
Browse files

New ColorConversions API

Should make it easier to switch implementations (to libswscale or to OpenCL).
Has some problems like being inited too early, so we've lost non-SSE2 Y420 conversion,
so it might crash on some files. I never did find any that caused the crash though.

git-svn-id: https://svn.perian.org/trunk@1531 621663c8-3916-0410-8f58-edc14a8543d5
  • Loading branch information...
astrange
astrange committed Nov 16, 2012
1 parent 36d1a9a commit 82701473d02611e469a0c775b0fe084a89c9eee5
Showing with 246 additions and 85 deletions.
  1. +153 −47 ColorConversions.c
  2. +30 −15 ColorConversions.h
  3. +27 −0 FFmpegUtils.c
  4. +2 −0 FFmpegUtils.h
  5. +33 −22 FFusionCodec.c
  6. +1 −1 Perian.xcodeproj/project.pbxproj
@@ -20,7 +20,6 @@
*/

#include <QuickTime/QuickTime.h>
#include <Accelerate/Accelerate.h>
#include "ColorConversions.h"
#include "Codecprintf.h"
#include "CommonUtils.h"
@@ -34,8 +33,15 @@
- handle YUV 4:2:0 with odd width
*/

#ifdef __GNUC__
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
#define impossible(x) if (x) __builtin_unreachable()
#else
#define unlikely(x) x
#define likely(x) x
#define impossible(x)
#endif

//Handles the last row for Y420 videos with an odd number of luma rows
//FIXME: odd number of luma columns is not handled and they will be lost
@@ -60,12 +66,14 @@ static void Y420toY422_lastrow(UInt8 *o, UInt8 *yc, UInt8 *uc, UInt8 *vc, int ha
#include <emmintrin.h>

static FASTCALL void Y420toY422_sse2(AVPicture *picture, UInt8 *o, int outRB, int width, int height)
{
{
UInt8 *yc = picture->data[0], *uc = picture->data[1], *vc = picture->data[2];
int rY = picture->linesize[0], rUV = picture->linesize[1];
int y, x, halfwidth = width >> 1, halfheight = height >> 1;
int vWidth = width >> 5;

impossible(width <= 1 || height <= 1 || outRB <= 0 || rY <= 0 || rUV <= 0);

for (y = 0; y < halfheight; y++) {
UInt8 *o2 = o + outRB, *yc2 = yc + rY;
__m128i *ov = (__m128i*)o, *ov2 = (__m128i*)o2, *yv = (__m128i*)yc, *yv2 = (__m128i*)yc2;
@@ -168,6 +176,8 @@ static FASTCALL void Y420toY422_x86_scalar(AVPicture *picture, UInt8 *o, int out
int halfheight = height >> 1, halfwidth = width >> 1;
int y, x;

impossible(width <= 1 || height <= 1 || outRB <= 0 || rY <= 0 || rUV <= 0);

for (y = 0; y < halfheight; y ++) {
UInt8 *o2 = o + outRB, *yc2 = yc + rY;

@@ -186,7 +196,7 @@ static FASTCALL void Y420toY422_x86_scalar(AVPicture *picture, UInt8 *o, int out
u += rUV;
v += rUV;
}

HandleLastRow(o, yc, u, v, halfwidth, height);
}

@@ -198,6 +208,8 @@ static FASTCALL void YA420toV408(AVPicture *picture, UInt8 *o, int outRB, int wi
int rYA = picture->linesize[0], rUV = picture->linesize[1];
int y, x;

impossible(width <= 0 || height <= 0 || outRB <= 0 || rYA <= 0 || rUV <= 0);

for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
o[x*4] = u[x>>1];
@@ -222,6 +234,8 @@ static FASTCALL void BGR24toRGB24(AVPicture *picture, UInt8 *baseAddr, int rowBy
int srcRB = picture->linesize[0];
int x, y;

impossible(width <= 0 || height <= 0 || srcRB <= 0 || rowBytes <= 0);

for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
@@ -303,6 +317,8 @@ static FASTCALL void Y422toY422(AVPicture *picture, UInt8 *o, int outRB, int wid
int rY = picture->linesize[0], rUV = picture->linesize[1];
int x, y, halfwidth = width >> 1;

impossible(width <= 0 || height <= 1 || outRB <= 0 || rY <= 0 || rUV <= 0);

for (y = 0; y < height; y++) {
for (x = 0; x < halfwidth; x++) {
int x2 = x * 2, x4 = x * 4;
@@ -404,95 +420,185 @@ static FASTCALL void ClearY422(UInt8 *baseAddr, int rowBytes, int width, int hei
}
}

OSType ColorConversionDstForPixFmt(enum PixelFormat ffPixFmt)
enum CCConverterType {
kCCConverterSimple,
kCCConverterSwscale,
kCCConverterOpenCL
};

static const enum CCConverterType kConverterType = kCCConverterSimple;

static enum PixelFormat CCSimplePixFmtForInput(enum PixelFormat inPixFmt)
{
switch (ffPixFmt) {
enum PixelFormat outPixFmt;

switch (inPixFmt) {
case PIX_FMT_RGB555LE:
case PIX_FMT_RGB555BE:
return k16BE555PixelFormat;
outPixFmt = PIX_FMT_RGB555BE;
break;
case PIX_FMT_BGR24:
return k24RGBPixelFormat; //FIXME: try k24BGRPixelFormat
case PIX_FMT_RGB24:
return k24RGBPixelFormat;
outPixFmt = PIX_FMT_RGB24;
break;
case PIX_FMT_ARGB:
case PIX_FMT_BGRA:
return k32ARGBPixelFormat;
outPixFmt = PIX_FMT_ARGB;
break;
case PIX_FMT_YUV410P:
return k2vuyPixelFormat;
case PIX_FMT_YUVJ420P:
case PIX_FMT_YUV420P:
return k2vuyPixelFormat; //disables "fast YUV" path
case PIX_FMT_YUV422P:
return k2vuyPixelFormat;
outPixFmt = PIX_FMT_YUV422P;
break;
case PIX_FMT_YUVA420P:
return k4444YpCbCrA8PixelFormat;
outPixFmt = PIX_FMT_YUV444P; // not quite...
break;
case PIX_FMT_YUV420P10LE:
// k422YpCbCr10CodecType? k2vuyPixelFormat? straight to RGB?
// same for full range 8-bit
default:
Codecprintf(NULL, "Unknown input pix fmt %d\n", inPixFmt);
outPixFmt = -1;
}

return outPixFmt;
}

// Let's just not decode 1x1 images, saves time
static bool CCIsInvalidImage(CCConverterContext *ctx)
{
switch (ctx->inPixFmt) {
case PIX_FMT_YUVJ420P:
case PIX_FMT_YUV420P:
case PIX_FMT_YUVA420P:
if (ctx->width < 2 || ctx->height < 2) return true;
case PIX_FMT_YUV422P:
if (ctx->height < 2) return true;
default:
return 0; // error
;
}

return false;
}

int ColorConversionFindFor(ColorConversionFuncs *funcs, enum PixelFormat ffPixFmt, AVPicture *ffPicture, OSType qtPixFmt)
static void CCOpenSimpleConverter(CCConverterContext *ctx)
{
switch (ffPixFmt) {
void (*convert)(AVPicture *inPicture, UInt8 *outBaseAddr, int outRowBytes, int outWidth, int outHeight) FASTCALL;
void (*clear)(UInt8 *outBaseAddr, int outRowBytes, int outWidth, int outHeight) FASTCALL;

void (^convertBlock)(AVPicture*, uint8_t*) FASTCALL = nil;
void (^clearBlock)(uint8_t*) FASTCALL = nil;

switch (ctx->inPixFmt) {
case PIX_FMT_YUVJ420P:
case PIX_FMT_YUV420P:
funcs->clear = ClearY422;

//can't set this without the first real frame
if (ffPicture) {
if (ffPicture->linesize[0] & 15)
funcs->convert = Y420toY422_x86_scalar;
else
funcs->convert = Y420toY422_sse2;
}
clear = ClearY422;
convert = Y420toY422_sse2;
break;
case PIX_FMT_BGR24:
funcs->clear = ClearRGB24;
funcs->convert = BGR24toRGB24;
clear = ClearRGB24;
convert = BGR24toRGB24;
break;
case PIX_FMT_ARGB:
funcs->clear = ClearRGB32;
clear = ClearRGB32;
#ifdef __BIG_ENDIAN__
funcs->convert = RGB32toRGB32Swap;
convert = RGB32toRGB32Swap;
#else
funcs->convert = RGB32toRGB32Copy;
convert = RGB32toRGB32Copy;
#endif
break;
case PIX_FMT_BGRA:
funcs->clear = ClearRGB32;
clear = ClearRGB32;
#ifdef __BIG_ENDIAN__
funcs->convert = RGB32toRGB32Copy;
convert = RGB32toRGB32Copy;
#else
funcs->convert = RGB32toRGB32Swap;
convert = RGB32toRGB32Swap;
#endif
break;
case PIX_FMT_RGB24:
funcs->clear = ClearRGB24;
funcs->convert = RGB24toRGB24;
clear = ClearRGB24;
convert = RGB24toRGB24;
break;
case PIX_FMT_RGB555LE:
funcs->clear = ClearRGB16;
funcs->convert = RGB16toRGB16Swap;
clear = ClearRGB16;
convert = RGB16toRGB16Swap;
break;
case PIX_FMT_RGB555BE:
funcs->clear = ClearRGB16;
funcs->convert = RGB16toRGB16;
clear = ClearRGB16;
convert = RGB16toRGB16;
break;
case PIX_FMT_YUV410P:
funcs->clear = ClearY422;
funcs->convert = Y410toY422;
clear = ClearY422;
convert = Y410toY422;
break;
case PIX_FMT_YUV422P:
funcs->clear = ClearY422;
funcs->convert = Y422toY422;
clear = ClearY422;
convert = Y422toY422;
break;
case PIX_FMT_YUVA420P:
funcs->clear = ClearV408;
funcs->convert = YA420toV408;
clear = ClearV408;
convert = YA420toV408;
break;
default:
return paramErr;
;
}

return noErr;
if (!convertBlock)
convertBlock = ^(AVPicture *inPicture, UInt8 *outPicture) FASTCALL {
convert(inPicture, outPicture, ctx->outLineSize, ctx->width, ctx->height);
};

if (!clearBlock)
clearBlock = ^(uint8_t *outPicture) FASTCALL {
clear(outPicture, ctx->outLineSize, ctx->width, ctx->height);
};

ctx->convert = Block_copy(convertBlock);
ctx->clear = Block_copy(clearBlock);
}

enum PixelFormat CCOutputPixFmtForInput(enum PixelFormat inPixFmt)
{
switch (kConverterType) {
case kCCConverterSimple:
default:
return CCSimplePixFmtForInput(inPixFmt);
}
}

void CCOpenConverter(CCConverterContext *ctx)
{
if (CCIsInvalidImage(ctx)) return;

ctx->type = kCCConverterSimple;

switch (ctx->type) {
case kCCConverterSimple:
ctx->outPixFmt = CCSimplePixFmtForInput(ctx->inPixFmt);
if (ctx->outPixFmt == -1) return;
CCOpenSimpleConverter(ctx);
break;
case kCCConverterSwscale:
//CCOpenSwscaleConverter(ctx);
break;
case kCCConverterOpenCL:
//CCOpenCLConverter(ctx);
break;
}
}

void CCCloseConverter(CCConverterContext *ctx)
{
switch (ctx->type) {
case kCCConverterSimple:
if (!ctx->convert) return;
Block_release(ctx->convert);
Block_release(ctx->clear);
break;
case kCCConverterSwscale:
break;
case kCCConverterOpenCL:
break;
}
}
@@ -25,24 +25,39 @@
#include <Carbon/Carbon.h>
#include "libavcodec/avcodec.h"

#if defined(__i386__) && !defined(__llvm__)
#if defined(__i386__)
#define FASTCALL __attribute__((fastcall))
#else
#define FASTCALL
#endif

typedef void ColorConversionFunc(AVPicture *inPicture, UInt8 *outBaseAddr, int outRowBytes, int outWidth, int outHeight) FASTCALL;
typedef void ColorClearFunc(UInt8 *outBaseAddr, int outRowBytes, int outWidth, int outHeight) FASTCALL;

typedef ColorConversionFunc *ColorConversionFuncPtr;
typedef ColorClearFunc *ColorClearFuncPtr;

typedef struct ColorConversionFuncs {
ColorConversionFuncPtr convert;
ColorClearFuncPtr clear;
} ColorConversionFuncs;

extern OSType ColorConversionDstForPixFmt(enum PixelFormat ffPixFmt);
extern int ColorConversionFindFor(ColorConversionFuncs *funcs, enum PixelFormat ffPixFmt, AVPicture *ffPicture, OSType qtPixFmt);

// Converts libavcodec pixel formats to QT displayable pixel formats
// All parameters except buffer pointers are fixed for each frame
typedef struct CCConverterContext {
// Input picture
int inLineSizes[4];
short width;
short height;

enum PixelFormat inPixFmt;
enum AVColorRange inColorRange;
enum AVChromaLocation inChromaLocation;

// Output picture
int outLineSize;

// Parameters end here
enum PixelFormat outPixFmt;

void (^convert)(AVPicture *inPicture, uint8_t *outPicture) FASTCALL;
void (^clear)(uint8_t *picture) FASTCALL;

// Private
int type;
void *opaque;
} CCConverterContext;

enum PixelFormat CCOutputPixFmtForInput(enum PixelFormat inPixFmt);
void CCOpenConverter(CCConverterContext *ctx);
void CCCloseConverter(CCConverterContext *ctx);
#endif
Oops, something went wrong.

0 comments on commit 8270147

Please sign in to comment.
You can’t perform that action at this time.