Permalink
Browse files

Swscale-based colorspace converter for reference

Not compiled by default, adds ~900kb to the binary.

Properly upsizes chroma and respects all colorspace attributes, so stairstep artifacts
on red/black aren't visible. Kind of slow.

git-svn-id: https://svn.perian.org/trunk@1536 621663c8-3916-0410-8f58-edc14a8543d5
  • Loading branch information...
astrange
astrange committed Nov 16, 2012
1 parent 954110e commit 783501f5495e153b93568b0b6a9f1f7acd91f1e4
Showing with 142 additions and 12 deletions.
  1. +123 −9 ColorConversions.c
  2. +1 −0 ColorConversions.h
  3. +3 −2 FFusionCodec.c
  4. +15 −1 Perian.xcodeproj/project.pbxproj
View
@@ -24,6 +24,9 @@
#include "Codecprintf.h"
#include "CommonUtils.h"
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
/*
Converts (without resampling) from ffmpeg pixel formats to the ones QT accepts
@@ -33,6 +36,8 @@
- handle YUV 4:2:0 with odd width
*/
//#define ENABLE_SWSCALE
#ifdef __GNUC__
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
@@ -45,6 +50,8 @@
#define always_inline inline
#endif
#pragma mark Simple conversion functions
static always_inline void Y420toY422_lastrow(UInt8 * __restrict o, UInt8 * __restrict yc, UInt8 * __restrict uc, UInt8 * __restrict vc, int halfwidth)
{
int x;
@@ -458,6 +465,8 @@ static FASTCALL void Y410toY422(const CCConverterContext *ctx, const AVPicture *
}
}
#pragma mark Picture clearing functions
static void ClearRGB(const CCConverterContext *ctx, UInt8 * __restrict baseAddr, int bytesPerPixel)
{
short width = ctx->width, height = ctx->height;
@@ -527,13 +536,7 @@ static FASTCALL void ClearY422(const CCConverterContext *ctx, UInt8 * __restrict
}
}
enum CCConverterType {
kCCConverterSimple,
kCCConverterSwscale,
kCCConverterOpenCL
};
static const enum CCConverterType kConverterType = kCCConverterSimple;
#pragma mark Simple converter
static enum PixelFormat CCSimplePixFmtForInput(enum PixelFormat inPixFmt)
{
@@ -699,12 +702,116 @@ static void CCOpenSimpleConverter(CCConverterContext *ctx)
ctx->convert = Block_copy(convertBlock);
}
#pragma mark SWS converter
static void CCOpenSwscaleConverter(CCConverterContext *ctx)
{
struct SwsContext *sws;
int swsRange = ctx->inColorRange == AVCOL_RANGE_JPEG ? 1 : 0;
int swsCoeffCode;
float hShift=0, vShift=0;
const int *swsCoeff;
switch (ctx->inColorSpace) {
case AVCOL_SPC_SMPTE170M:
case AVCOL_SPC_SMPTE240M:
default:
swsCoeffCode = SWS_CS_ITU601;
break;
case AVCOL_SPC_BT709:
swsCoeffCode = SWS_CS_ITU709;
break;
case AVCOL_SPC_UNSPECIFIED:
swsCoeffCode = ctx->height > 576 ? SWS_CS_ITU709 : SWS_CS_ITU601;
break;
}
// TODO: should left be shifted .5, or should center be shifted -.5?
switch (ctx->inChromaLocation) {
case AVCHROMA_LOC_LEFT:
hShift = .5;
break;
case AVCHROMA_LOC_UNSPECIFIED:
case AVCHROMA_LOC_CENTER:
default:
break;
case AVCHROMA_LOC_TOPLEFT:
hShift = .5; vShift = .5;
break;
case AVCHROMA_LOC_TOP:
vShift = .5;
break;
case AVCHROMA_LOC_BOTTOMLEFT:
hShift = .5; vShift = -.5;
break;
case AVCHROMA_LOC_BOTTOM:
vShift = -.5;
}
Codecprintf(NULL, "Color space %d/%d, chroma loc %d (%f %f)\n", ctx->inColorSpace, swsCoeffCode, ctx->inChromaLocation, hShift, vShift);
swsCoeff = sws_getCoefficients(swsCoeffCode);
sws = sws_alloc_context();
av_opt_set_int(sws, "srcw", ctx->width, 0);
av_opt_set_int(sws, "srch", ctx->height, 0);
av_opt_set_int(sws, "dstw", ctx->width, 0);
av_opt_set_int(sws, "dsth", ctx->height, 0);
av_opt_set_int(sws, "src_format", ctx->inPixFmt, 0);
av_opt_set_int(sws, "dst_format", ctx->outPixFmt, 0);
av_opt_set_int(sws, "src_range", swsRange, 0);
av_opt_set(sws, "sws_flags", "bicubic+full_chroma_int", 0);
sws_setColorspaceDetails(sws, swsCoeff, swsRange, swsCoeff, 0, 0, 1<<16, 1<<16);
SwsFilter *srcFilter = sws_getDefaultFilter(0, .5, 0, 0, hShift, vShift, 0);
SwsFilter *dstFilter = sws_getDefaultFilter(0, 0, 0, 0, 0, 0, 0);
int err = sws_init_context(sws, srcFilter, dstFilter);
ctx->opaque = sws;
ctx->convert = Block_copy(^(AVPicture *inPicture, uint8_t *outPicture) FASTCALL {
uint8_t * const outdata[4] = {outPicture};
int outlinesize[4] = {ctx->outLineSize};
sws_scale(ctx->opaque,
(const uint8_t*const*)inPicture->data,
inPicture->linesize,
0, ctx->height,
outdata, outlinesize);
});
}
static void CCCloseSwscaleConverter(CCConverterContext *ctx)
{
sws_freeContext(ctx->opaque);
}
#pragma mark Color converter API
enum CCConverterType {
kCCConverterSimple,
kCCConverterSwscale,
kCCConverterOpenCL
};
#ifdef ENABLE_SWSCALE
static const enum CCConverterType kConverterType = kCCConverterSwscale;
#else
static const enum CCConverterType kConverterType = kCCConverterSimple;
#endif
enum PixelFormat CCOutputPixFmtForInput(enum PixelFormat inPixFmt)
{
switch (kConverterType) {
case kCCConverterSimple:
default:
return CCSimplePixFmtForInput(inPixFmt);
case kCCConverterSwscale:
return PIX_FMT_RGB24;
}
}
@@ -718,17 +825,20 @@ void CCOpenConverter(CCConverterContext *ctx)
{
if (CCIsInvalidImage(ctx)) return;
ctx->type = kCCConverterSimple;
ctx->type = kConverterType;
switch (ctx->type) {
case kCCConverterSimple:
ctx->outPixFmt = CCSimplePixFmtForInput(ctx->inPixFmt);
if (ctx->outPixFmt == -1) return;
CCOpenSimpleConverter(ctx);
break;
#ifdef ENABLE_SWSCALE
case kCCConverterSwscale:
//CCOpenSwscaleConverter(ctx);
ctx->outPixFmt = PIX_FMT_RGB24;
CCOpenSwscaleConverter(ctx);
break;
#endif
case kCCConverterOpenCL:
//CCOpenCLConverter(ctx);
break;
@@ -742,8 +852,12 @@ void CCCloseConverter(CCConverterContext *ctx)
if (!ctx->convert) return;
Block_release(ctx->convert);
break;
#ifdef ENABLE_SWSCALE
case kCCConverterSwscale:
CCCloseSwscaleConverter(ctx);
Block_release(ctx->convert);
break;
#endif
case kCCConverterOpenCL:
break;
}
View
@@ -40,6 +40,7 @@ typedef struct CCConverterContext {
short height;
enum PixelFormat inPixFmt;
enum AVColorSpace inColorSpace;
enum AVColorRange inColorRange;
enum AVChromaLocation inChromaLocation;
View
@@ -865,8 +865,8 @@ pascal ComponentResult FFusionCodecBeginBand(FFusionGlobals glob, CodecDecompres
return internalComponentErr;
}
if (p->frameNumber == 0 && p->dstPixMap.pixelFormat != **glob->pixelTypes) {
Codecprintf(glob->fileLog, "QT gave us unwanted pixelFormat %s (%08x), this will not work\n", FourCCString(p->dstPixMap.pixelFormat), (unsigned)p->dstPixMap.pixelFormat);
if (p->frameNumber <= 1 && p->dstPixMap.pixelFormat != **(OSType**)glob->pixelTypes) {
Codecprintf(NULL, "QT gave us unwanted pixelFormat %s (%08x), this will not work\n", FourCCString(p->dstPixMap.pixelFormat), (unsigned)p->dstPixMap.pixelFormat);
}
if(myDrp->decoded)
@@ -1203,6 +1203,7 @@ pascal ComponentResult FFusionCodecDrawBand(FFusionGlobals glob, ImageSubCodecDe
}
if (!colorConv->convert) {
colorConv->inColorSpace = glob->avContext->colorspace;
colorConv->inColorRange = glob->avContext->color_range;
colorConv->inChromaLocation = glob->avContext->chroma_sample_location;
memcpy(colorConv->inLineSizes, picture->linesize, sizeof(picture->linesize));
@@ -136,7 +136,7 @@
3D211A300B6B1AD80051299D /* SubParsing.m.rl in Sources */ = {isa = PBXBuildFile; fileRef = 3D211A2F0B6B1AD80051299D /* SubParsing.m.rl */; };
3D2A136F1213D3CC002BFAEA /* KaxDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D2A136E1213D3CC002BFAEA /* KaxDefines.h */; };
3D41BEB40BCD3B510069E7C2 /* libuniversaldetector.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D41BE9A0BCD3B330069E7C2 /* libuniversaldetector.a */; };
3D4A7A990B5533BC004C5D6A /* ColorConversions.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D4A7A980B5533BC004C5D6A /* ColorConversions.c */; settings = {COMPILER_FLAGS = "-O3"; }; };
3D4A7A990B5533BC004C5D6A /* ColorConversions.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D4A7A980B5533BC004C5D6A /* ColorConversions.c */; };
3D5AB53C10BB52B500D1E688 /* CommonUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = 61D517720AE0402E00A671E1 /* CommonUtils.c */; };
3D70B04B13CC187900711D41 /* KaxSemantic.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D70B04A13CC187900711D41 /* KaxSemantic.h */; };
3D70B04D13CC188300711D41 /* KaxSemantic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D70B04C13CC188300711D41 /* KaxSemantic.cpp */; };
@@ -668,6 +668,7 @@
3D802EC21032B9B50034BF4A /* ssa2pdf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ssa2pdf.m; path = Subtitles/ssa2pdf.m; sourceTree = "<group>"; };
3D802F8510336EE90034BF4A /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; };
3D95B9000E208965007C8F51 /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = /usr/lib/libbz2.dylib; sourceTree = "<absolute>"; };
3D9D088016563BEE0016C817 /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswscale.a; path = "DerivedData/Perian/Build/Products/Deployment+Debug/Universal/libswscale.a"; sourceTree = "<group>"; };
3DA6322312865F5400AC1962 /* FFmpegUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = FFmpegUtils.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
3DA6322412865F5400AC1962 /* FFmpegUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = FFmpegUtils.c; sourceTree = "<group>"; };
3DAD08080FBF7C6F001E156F /* ssa2html */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ssa2html; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1014,6 +1015,7 @@
11D4EFA10A3CE8C10066D45F /* libavcodec.a */,
8F483B540A642644002CCA73 /* libavformat.a */,
11D4EFA20A3CE8C10066D45F /* libavutil.a */,
3D9D088016563BEE0016C817 /* libswscale.a */,
11D4EEFC0A3CE7FA0066D45F /* Carbon.framework */,
11D4EED50A3CE7EC0066D45F /* QuickTime.framework */,
F53E18E40B4F483C003A0471 /* Security.framework */,
@@ -2358,6 +2360,10 @@
INFOPLIST_PREFIX_HEADER = "$(TARGET_BUILD_DIR)/include/SVNRevision.h";
INFOPLIST_PREPROCESS = YES;
INSTALL_PATH = "$(HOME)/Library/QuickTime";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/DerivedData/Perian/Build/Products/Deployment+Debug/Universal\"",
);
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"-read_only_relocs",
@@ -2397,6 +2403,10 @@
INFOPLIST_PREFIX_HEADER = "$(TARGET_BUILD_DIR)/include/SVNRevision.h";
INFOPLIST_PREPROCESS = YES;
INSTALL_PATH = "$(HOME)/Library/QuickTime";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/DerivedData/Perian/Build/Products/Deployment+Debug/Universal\"",
);
OTHER_LDFLAGS = (
"-read_only_relocs",
suppress,
@@ -2563,6 +2573,10 @@
INFOPLIST_PREFIX_HEADER = "$(TARGET_BUILD_DIR)/include/SVNRevision.h";
INFOPLIST_PREPROCESS = YES;
INSTALL_PATH = "$(HOME)/Library/QuickTime";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/DerivedData/Perian/Build/Products/Deployment+Debug/Universal\"",
);
OTHER_LDFLAGS = (
"-read_only_relocs",
suppress,

0 comments on commit 783501f

Please sign in to comment.