Index: libvo/osd.c =================================================================== RCS file: /cvsroot/mplayer/main/libvo/osd.c,v retrieving revision 1.21 diff -u -r1.21 osd.c --- libvo/osd.c 26 Apr 2004 10:12:40 -0000 1.21 +++ libvo/osd.c 30 Apr 2004 12:06:41 -0000 @@ -167,6 +167,36 @@ #endif //!RUNTIME_CPUDETECT } +void vo_draw_alpha_uyvy(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ +#ifdef RUNTIME_CPUDETECT +#ifdef CAN_COMPILE_X86_ASM + // ordered per speed fasterst first + if(gCpuCaps.hasMMX2) + vo_draw_alpha_uyvy_MMX2(w, h, src, srca, srcstride, dstbase, dststride); + else if(gCpuCaps.has3DNow) + vo_draw_alpha_uyvy_3DNow(w, h, src, srca, srcstride, dstbase, dststride); + else if(gCpuCaps.hasMMX) + vo_draw_alpha_uyvy_MMX(w, h, src, srca, srcstride, dstbase, dststride); + else + vo_draw_alpha_uyvy_X86(w, h, src, srca, srcstride, dstbase, dststride); +#else + vo_draw_alpha_uyvy_C(w, h, src, srca, srcstride, dstbase, dststride); +#endif +#else //RUNTIME_CPUDETECT +#ifdef HAVE_MMX2 + vo_draw_alpha_uyvy_MMX2(w, h, src, srca, srcstride, dstbase, dststride); +#elif defined (HAVE_3DNOW) + vo_draw_alpha_uyvy_3DNow(w, h, src, srca, srcstride, dstbase, dststride); +#elif defined (HAVE_MMX) + vo_draw_alpha_uyvy_MMX(w, h, src, srca, srcstride, dstbase, dststride); +#elif defined (ARCH_X86) + vo_draw_alpha_uyvy_X86(w, h, src, srca, srcstride, dstbase, dststride); +#else + vo_draw_alpha_uyvy_C(w, h, src, srca, srcstride, dstbase, dststride); +#endif +#endif //!RUNTIME_CPUDETECT +} + void vo_draw_alpha_rgb24(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ #ifdef RUNTIME_CPUDETECT #ifdef CAN_COMPILE_X86_ASM Index: libvo/osd.h =================================================================== RCS file: /cvsroot/mplayer/main/libvo/osd.h,v retrieving revision 1.3 diff -u -r1.3 osd.h --- libvo/osd.h 10 Jun 2001 22:25:09 -0000 1.3 +++ libvo/osd.h 30 Apr 2004 12:06:41 -0000 @@ -9,6 +9,7 @@ extern void vo_draw_alpha_yv12(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); extern void vo_draw_alpha_yuy2(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); +extern void vo_draw_alpha_uyvy(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); extern void vo_draw_alpha_rgb24(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); extern void vo_draw_alpha_rgb32(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); extern void vo_draw_alpha_rgb15(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride); Index: libvo/osd_template.c =================================================================== RCS file: /cvsroot/mplayer/main/libvo/osd_template.c,v retrieving revision 1.20 diff -u -r1.20 osd_template.c --- libvo/osd_template.c 3 Aug 2003 18:33:28 -0000 1.20 +++ libvo/osd_template.c 30 Apr 2004 12:06:41 -0000 @@ -160,6 +160,30 @@ return; } +static inline void RENAME(vo_draw_alpha_uyvy)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ + int y; +#if defined(FAST_OSD) + w=w>>1; +#endif + for(y=0;y>8)+src[x]; + dstbase[2*x]=((((signed)dstbase[2*x]-128)*srca[x])>>8)+128; + } +#endif + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } +} + static inline void RENAME(vo_draw_alpha_rgb24)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ int y; for(y=0;y Copyright (c) Nicolas Plourde - April 2004 + + YUV support Copyright (C) 2004 Romain Dolbeau MPlayer Mac OSX Quartz video out module. - todo: -YUV support. - -Redo event handling. + todo: -Redo event handling. -Choose fullscreen display device. -Fullscreen antialiasing. -resize black bar without CGContext -rootwin -non-blocking event -(add sugestion here) + + Direct YUV support is functional, and is now enabled + by default. The formats accepted by the driver as input + can be constrained by using the use_XXX options. If at + least one is mentioned, the driver will only accept the + color formats passed as option, otherwise it accepts + everything. Available color format are: + # use_rgb (32 bits packed ARGB) + # use_yv12 or use_i420 or use_iyuv use_y420 (planar YUV) + # use_yuy2 or use_yuvs (packed YUV) + # use_uyvy or use_2vuy (another packed YUV) */ //SYS @@ -22,23 +34,29 @@ //OSX #include +#include //MPLAYER #include "config.h" +#include "fastmemcpy.h" #include "video_out.h" #include "video_out_internal.h" #include "aspect.h" +#include "mp_msg.h" +#include "m_option.h" #include "../input/input.h" #include "../input/mouse.h" #include "vo_quartz.h" +#define QUARTZ_ENABLE_YUV + static vo_info_t info = { "Mac OSX (Quartz)", "quartz", - "Nicolas Plourde ", + "Nicolas Plourde , Romain Dolbeau ", "" }; @@ -47,8 +65,30 @@ uint32_t image_width; uint32_t image_height; uint32_t image_depth; -uint32_t image_bytes; uint32_t image_format; +uint32_t image_size; + +#ifdef QUARTZ_ENABLE_YUV +static CodecType image_qtcodec; +static PlanarPixmapInfoYUV420 *P; +static struct { + ImageSequence seqId; + ImageDescriptionHandle desc; + Handle extension_colr; + Handle extension_fiel; + Handle extension_clap; + Handle extension_pasp; + MatrixRecord matrix; +} yuv_qt_stuff; +static DecompressorComponent mycodec; +static ComponentInstance myopenedcodec; +static int quartz_use_rgb = 0; +static int quartz_use_yv12 = 0; +static int quartz_use_yuy2 = 0; +static int quartz_use_uyvy = 0; +static int quartz_forced_mode = 0; +static int EnterMoviesDone = 0; +#endif char *image_data; extern int vo_ontop; @@ -64,8 +104,7 @@ GWorldPtr imgGWorld; Rect imgRect; -Rect dstRect; -Rect winRect; +Rect dstRect;Rect winRect; CGContextRef context; @@ -85,7 +124,24 @@ static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { - vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*imgRect.right+x0),4*imgRect.right); + switch (image_format) { + case IMGFMT_RGB32: + vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*imgRect.right+x0),4*imgRect.right); + break; +#ifdef QUARTZ_ENABLE_YUV + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + vo_draw_alpha_yv12(w,h,src,srca,stride,((char*)P) + P->componentInfoY.offset,image_width); + break; + case IMGFMT_UYVY: + vo_draw_alpha_uyvy(w,h,src,srca,stride,((char*)P),image_width*2); + break; + case IMGFMT_YUY2: + vo_draw_alpha_yuy2(w,h,src,srca,stride,((char*)P),image_width*2); + break; +#endif + } } //default window event handler @@ -243,6 +299,7 @@ OSStatus result; GDHandle deviceHdl; Rect deviceRect; + OSErr qterr; //Get Main device info/////////////////////////////////////////////////// deviceHdl = GetMainDevice(); @@ -254,9 +311,22 @@ //misc mplayer setup///////////////////////////////////////////////////// image_width = width; image_height = height; - image_depth = IMGFMT_RGB_DEPTH(format); - image_bytes = (IMGFMT_RGB_DEPTH(format)+7)/8; - image_data = malloc(image_width*image_height*4); + switch (image_format) { + case IMGFMT_RGB32: + image_depth = IMGFMT_RGB_DEPTH(format); + break; +#ifdef QUARTZ_ENABLE_YUV + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + image_depth = 12; + case IMGFMT_UYVY: + case IMGFMT_YUY2: + image_depth = 16; + break; +#endif + } + image_size = ((image_width*image_height*image_depth)+7)/8; vo_fs = flags & VOFLAG_FULLSCREEN; @@ -268,9 +338,9 @@ aspect(&d_width,&d_height,A_NOZOOM); //Create player window////////////////////////////////////////////////// - windowAttrs = kWindowStandardDocumentAttributes + windowAttrs = kWindowStandardDocumentAttributes & ~(kWindowResizableAttribute) | kWindowStandardHandlerAttribute - | kWindowLiveResizeAttribute; + ;//| kWindowLiveResizeAttribute; SetRect(&winRect, 0, 0, d_width, d_height); SetRect(&dstRect, 0, 0, d_width, d_height); @@ -296,6 +366,227 @@ //Show window RepositionWindow(theWindow, NULL, kWindowCascadeOnMainScreen); +#ifdef QUARTZ_ENABLE_YUV + if (!(IMGFMT_IS_RGB(image_format))) { + if (!EnterMoviesDone) { + qterr = EnterMovies(); + EnterMoviesDone = 1; + } + else + qterr = 0; + mp_msg(MSGT_VO, MSGL_INFO, "\nQuartz: EnterMovies\n"); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: EnterMovies (%d)\n", qterr); + } + + +#if 0 // can be handy for developers, but useless for users + { + CodecNameSpecListPtr list; + int index; + qterr = GetCodecNameList(&list, 1); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: GetCodecNameList (%d)\n", qterr); + } + mp_msg(MSGT_VO, MSGL_ERR, "Quartz: found %d codec\n", list->count); + + for (index = 0; index < list->count; index++) { + char name[32]; + CodecInfo ci; + + memcpy(name, &(list->list[index].typeName[1]), list->list[index].typeName[0]); + name[list->list[index].typeName[0]]='\0'; + qterr = GetCodecInfo(&ci, list->list[index].cType, list->list[index].codec); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: GetCodecInfo (%d)\n", qterr); + } + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: QuickTimecodec %d:\n\tname: %s\n\ttype: %.4s\n\tvendor: %.4s\n\tversion/revision: %d/%d\n\tdecompressFlags: 0x%08x\n\tcompressFlags: 0x%08x\n\tformatFlags: 0x%08x\n", index, name, &list->list[index].cType, &ci.vendor, ci.version, ci.revisionLevel, ci.decompressFlags, ci.compressFlags, ci.formatFlags); + } + } + { + Component c = NULL; + ComponentDescription cd; + cd.componentType = 'imdc'; + cd.componentSubType = image_qtcodec; + cd.componentManufacturer = 0;//'appx'; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + + while (c = FindNextComponent(c, &cd)) { + ComponentDescription cd2; + Handle h1 = NewHandleClear(4); + Handle h2 = NewHandleClear(4); + char ch1[256], ch2[256]; + cd2.componentFlagsMask = 0; + + qterr = GetComponentInfo(c, &cd2, h1, h2, NULL); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: GetComponentInfo (%d)\n", qterr); + } + memcpy(ch1, &((char*)(*h1))[1], ((char*)(*h1))[0]); + ch1[((char*)(*h1))[0]] = '\0'; + memcpy(ch2, &((char*)(*h2))[1], ((char*)(*h2))[0]); + ch2[((char*)(*h2))[0]] = '\0'; + DisposeHandle(h1); + DisposeHandle(h2); + + mp_msg(MSGT_VO, MSGL_ERR, "QuickTime: component %.4s %.4s %.4s, %s, %s, [flags: 0x%08x, mask: 0x%08x]\n", + &cd2.componentType, + &cd2.componentSubType, + &cd2.componentManufacturer, + ch1, + ch2, + cd2.componentFlags, + cd2.componentFlagsMask); + } + } +#endif + { + ComponentDescription cd2; + Handle h1 = NewHandleClear(4); + Handle h2 = NewHandleClear(4); + char ch1[256], ch2[256]; + + qterr = FindCodec(image_qtcodec, bestSpeedCodec, NULL, &mycodec); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: FindCodec (%d)\n", qterr); + } + qterr = GetComponentInfo(mycodec, &cd2, h1, h2, NULL); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: GetComponentInfo (%d)\n", qterr); + } + memcpy(ch1, &((char*)(*h1))[1], ((char*)(*h1))[0]); + ch1[((char*)(*h1))[0]] = '\0'; + memcpy(ch2, &((char*)(*h2))[1], ((char*)(*h2))[0]); + ch2[((char*)(*h2))[0]] = '\0'; + DisposeHandle(h1); + DisposeHandle(h2); + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: QuickTime FindCodec reports component %.4s %.4s %.4s, %s, %s, [flags: 0x%08x, mask: 0x%08x]\n", + &cd2.componentType, + &cd2.componentSubType, + &cd2.componentManufacturer, + ch1, + ch2, + cd2.componentFlags, + cd2.componentFlagsMask); + + { + CodecInfo ci; + qterr = GetCodecInfo(&ci, 'imdc', mycodec); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: GetCodecInfo (%d)\n", qterr); + } + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: CodecInfo:\n\tname: %s\n\tvendor: %.4s\n\tversion/revision: %d/%d\n\tdecompressFlags: 0x%08x\n\tcompressFlags: 0x%08x\n\tformatFlags: 0x%08x\n", ch1, &ci.vendor, ci.version, ci.revisionLevel, ci.decompressFlags, ci.compressFlags, ci.formatFlags); + } + } + yuv_qt_stuff.desc = (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) ); + yuv_qt_stuff.extension_colr = NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension)); + ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->colorParamType = kVideoColorInfoImageDescriptionExtensionType; + ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->primaries = 2; + ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->transferFunction = 2; + ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->matrix = 2; + yuv_qt_stuff.extension_fiel = NewHandleClear(sizeof(FieldInfoImageDescriptionExtension)); + ((FieldInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_fiel))->fieldCount = 1; + ((FieldInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_fiel))->fieldOrderings = 0; + yuv_qt_stuff.extension_clap = NewHandleClear(sizeof(CleanApertureImageDescriptionExtension)); + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureWidthN = image_width; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureWidthD = 1; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureHeightN = image_height; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureHeightD = 1; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->horizOffN = 0; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->horizOffD = 1; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->vertOffN = 0; + ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->vertOffD = 1; + yuv_qt_stuff.extension_pasp = NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension)); + ((PixelAspectRatioImageDescriptionExtension*)(*yuv_qt_stuff.extension_pasp))->hSpacing = 1; + ((PixelAspectRatioImageDescriptionExtension*)(*yuv_qt_stuff.extension_pasp))->vSpacing = 1; + + (*yuv_qt_stuff.desc)->idSize = sizeof(ImageDescription); + (*yuv_qt_stuff.desc)->cType = image_qtcodec; + (*yuv_qt_stuff.desc)->version = 2; + (*yuv_qt_stuff.desc)->revisionLevel = 0; + (*yuv_qt_stuff.desc)->vendor = 'mpla'; + (*yuv_qt_stuff.desc)->width = image_width; + (*yuv_qt_stuff.desc)->height = image_height; + (*yuv_qt_stuff.desc)->hRes = Long2Fix(72); + (*yuv_qt_stuff.desc)->vRes = Long2Fix(72); + (*yuv_qt_stuff.desc)->temporalQuality = 0; + (*yuv_qt_stuff.desc)->spatialQuality = codecLosslessQuality; + (*yuv_qt_stuff.desc)->frameCount = 1; + (*yuv_qt_stuff.desc)->dataSize = 0; + (*yuv_qt_stuff.desc)->depth = 24; + (*yuv_qt_stuff.desc)->clutID = -1; + + qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_colr, kColorInfoImageDescriptionExtension); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr); + } + qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_fiel, kFieldInfoImageDescriptionExtension); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr); + } + qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_clap, kCleanApertureImageDescriptionExtension); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr); + } + qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_pasp, kCleanApertureImageDescriptionExtension); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr); + } + + SetPort(GetWindowPort(theWindow)); + SetIdentityMatrix(&yuv_qt_stuff.matrix); + if ((d_width != width) || (d_height != height)) { + ScaleMatrix(&yuv_qt_stuff.matrix, + FixDiv(Long2Fix(d_width),Long2Fix(width)), + FixDiv(Long2Fix(d_height),Long2Fix(height)), + 0, + 0); + } + P = calloc(sizeof(PlanarPixmapInfoYUV420) + image_width * image_height * 2, 1); + switch (image_format) { + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + P->componentInfoY.offset = sizeof(PlanarPixmapInfoYUV420); + P->componentInfoCb.offset = P->componentInfoY.offset + image_width * image_height; + P->componentInfoCr.offset = P->componentInfoCb.offset + (image_width * image_height) / 4; + P->componentInfoY.rowBytes = image_width; + P->componentInfoCb.rowBytes = image_width / 2; + P->componentInfoCr.rowBytes = image_width / 2; + break; + case IMGFMT_UYVY: + case IMGFMT_YUY2: + break; + } + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: DecompressSequenceBeginS\n"); + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: width=%d, height=%d, d_width=%d, d_height=%d\n", + width, height, d_width, d_height); + myopenedcodec = OpenComponent(mycodec); + + qterr = DecompressSequenceBeginS(&yuv_qt_stuff.seqId, + yuv_qt_stuff.desc, + P, + image_width * image_height * 2, + NULL, //GetWindowPort(theWindow), + NULL, // GDHandle + NULL, // srcRect + ((d_width != width) || (d_height != height)) ? + &yuv_qt_stuff.matrix : NULL, + srcCopy, + NULL, // mask, + 0, //codecFlagUseImageBuffer, + codecLosslessQuality, + bestSpeedCodec); + //mycodec); // some codec reported by FindCodec() won't work + //myopenedcodec); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr); + } + mp_msg(MSGT_VO, MSGL_INFO, "Quartz: DecompressSequenceBeginS done\n"); + } +#endif /* QUARTZ_ENABLE_YUV */ + ShowWindow (theWindow); if(vo_fs) @@ -345,12 +636,15 @@ static void flip_page(void) { + switch (image_format) { + case IMGFMT_RGB32: + { OSStatus error; CGrafPtr oldPort,deskPort; GDHandle oldGDevice; OSStatus lockPixelsError; Boolean canLockPixels; - + GetGWorld (&oldPort, &oldGDevice); SetGWorld(GetWindowPort(theWindow), GetMainDevice()); @@ -380,30 +674,114 @@ } SetGWorld(oldPort, oldGDevice); + } + break; +#ifdef QUARTZ_ENABLE_YUV + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + case IMGFMT_UYVY: + case IMGFMT_YUY2: + if (EnterMoviesDone) { + OSErr qterr; + CodecFlags flags = 0; + qterr = DecompressSequenceFrameWhen(yuv_qt_stuff.seqId, + P, + image_width * image_height * 2, + codecFlagUseImageBuffer, + &flags, + NULL, + NULL); + if (qterr) { + mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags); + } + } + break; +#endif + } } static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) { +#ifdef QUARTZ_ENABLE_YUV + switch (image_format) { + case IMGFMT_YV12: + case IMGFMT_I420: + memcpy_pic(((char*)P) + P->componentInfoY.offset + x + image_width * y, src[0], + w, h, image_width, stride[0]); + x=x/2;y=y/2;w=w/2;h=h/2; + memcpy_pic(((char*)P) + P->componentInfoCb.offset + x + image_width / 2 * y, src[1], + w, h, image_width / 2, stride[1]); + memcpy_pic(((char*)P) + P->componentInfoCr.offset + x + image_width / 2 * y, src[2], + w, h, image_width / 2, stride[2]); + return 0; + + case IMGFMT_IYUV: + memcpy_pic(((char*)P) + P->componentInfoY.offset + x + image_width * y, src[0], + w, h, image_width, stride[0]); + x=x/2;y=y/2;w=w/2;h=h/2; + memcpy_pic(((char*)P) + P->componentInfoCr.offset + x + image_width / 2 * y, src[1], + w, h, image_width / 2, stride[1]); + memcpy_pic(((char*)P) + P->componentInfoCb.offset + x + image_width / 2 * y, src[2], + w, h, image_width / 2, stride[2]); + return 0; + } +#endif return -1; } static uint32_t draw_frame(uint8_t *src[]) { + switch (image_format) { + case IMGFMT_RGB32: image_data = src[0]; - DisposeGWorld(imgGWorld); NewGWorldFromPtr (&imgGWorld, k32ARGBPixelFormat, &imgRect, 0, 0, 0, image_data, image_width * 4); - - return 0; + return 0; +#ifdef QUARTZ_ENABLE_YUV + case IMGFMT_UYVY: + case IMGFMT_YUY2: + memcpy_pic(((char*)P), src[0], image_width * 2, image_height, image_width * 2, image_width * 2); + return 0; +#endif + } + return -1; } static uint32_t query_format(uint32_t format) { image_format = format; - //Curently supporting only rgb32 format. - if ((format == IMGFMT_RGB32)) - return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW; + if ((format == IMGFMT_RGB32) && + (!quartz_forced_mode || + quartz_use_rgb)) + return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE | VFCAP_CSP_SUPPORTED_BY_HW; + +#ifdef QUARTZ_ENABLE_YUV + image_qtcodec = 0; + + if (((format == IMGFMT_YV12) || (format == IMGFMT_IYUV) || (format == IMGFMT_I420)) && + (!quartz_forced_mode || + quartz_use_yv12)) { + image_qtcodec = kMpegYUV420CodecType; //kYUV420CodecType; + return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE | VFCAP_ACCEPT_STRIDE; + } + + if (((format == IMGFMT_YUY2)) && + (!quartz_forced_mode || + quartz_use_yuy2)) { + image_qtcodec = kComponentVideoUnsigned; + return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE; + } + + if (((format == IMGFMT_UYVY)) && + (!quartz_forced_mode || + quartz_use_uyvy)) { + image_qtcodec = k422YpCbCr8CodecType; + return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE; + } +#endif + return 0; } @@ -414,8 +792,102 @@ static uint32_t preinit(const char *arg) { - return 0; + if (arg != NULL) { + char *arg2 = calloc(strlen(arg) + 2, 1); + char *current = arg2; + int i = 0; + strcpy(arg2, arg); + + while (current[0] != '\0') { + i = strcspn(current, ":"); + current[i] = '\0'; + if (!strncmp(current, "use_rgb", i)) + quartz_use_rgb = 1; else + if ((!strncmp(current, "use_yv12", i)) || // mplayer + (!strncmp(current, "use_iyuv", i)) || // mplayer + (!strncmp(current, "use_i420", i))) // mplayer + quartz_use_yv12 = 1; else + if ((!strncmp(current, "use_y420", i)) || // apple + (!strncmp(current, "use_myuv", i))) // apple + quartz_use_yv12 = 1; else + if (!strncmp(current, "use_yuy2", i)) // mplayer + quartz_use_yuy2 = 1; else + if (!strncmp(current, "use_yuvs", i)) // apple + quartz_use_yuy2 = 1; else + if (!strncmp(current, "use_uyvy", i)) // mplayer + quartz_use_uyvy = 1; else + if (!strncmp(current, "use_2vuy", i)) // apple + quartz_use_uyvy = 1; else { + mp_msg(MSGT_VO, MSGL_ERR, "Quartz: unknown option ! (%s)\n", current); + } + + current += (i+1); + } + free(arg2); + } + + if (quartz_use_rgb || + quartz_use_yv12 || + quartz_use_uyvy || + quartz_use_yuy2) + quartz_forced_mode = 1; + + return 0; +} + +#ifdef QUARTZ_ENABLE_YUV +static uint32_t draw_yuv_image(mp_image_t *mpi) { + // ATM we're only called for planar IMGFMT + // drawing is done directly in P + // and displaying is in flip_page. + return VO_TRUE; +} + +static uint32_t get_yuv_image(mp_image_t *mpi) { + if(mpi->type!=MP_IMGTYPE_EXPORT) return VO_FALSE; + + if(mpi->imgfmt!=image_format) return VO_FALSE; + + if(mpi->flags&MP_IMGFLAG_PLANAR){ + if (mpi->num_planes != 3) { + mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi->num_planes); + return VO_FALSE; + } + + mpi->planes[0]=((char*)P) + P->componentInfoY.offset; + mpi->stride[0]=image_width; + mpi->width=image_width; + + if(mpi->flags&MP_IMGFLAG_SWAPPED){ + // I420 + mpi->planes[1]=((char*)P) + P->componentInfoCb.offset; + mpi->planes[2]=((char*)P) + P->componentInfoCr.offset; + mpi->stride[1]=image_width/2; + mpi->stride[2]=image_width/2; + } else { + // YV12 + mpi->planes[1]=((char*)P) + P->componentInfoCr.offset; + mpi->planes[2]=((char*)P) + P->componentInfoCb.offset; + mpi->stride[1]=image_width/2; + mpi->stride[2]=image_width/2; + } + mpi->flags|=MP_IMGFLAG_DIRECT; + return VO_TRUE; + } else { // doesn't work yet + if (mpi->num_planes != 1) { + mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi->num_planes); + return VO_FALSE; + } + + mpi->planes[0] = (char*)P; + mpi->stride[0] = image_width * 2; + mpi->width=image_width; + mpi->flags|=MP_IMGFLAG_DIRECT; + return VO_TRUE; + } + return VO_FALSE; } +#endif /* QUARTZ_ENABLE_YUV */ static uint32_t control(uint32_t request, void *data, ...) { @@ -426,6 +898,28 @@ case VOCTRL_FULLSCREEN: window_fullscreen(); return VO_TRUE; case VOCTRL_ONTOP: window_ontop(); return VO_TRUE; case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t*)data)); +#ifdef QUARTZ_ENABLE_YUV + case VOCTRL_GET_IMAGE: + switch (image_format) { + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + //case IMGFMT_UYVY: + //case IMGFMT_YUY2: + return get_yuv_image(data); + break; + } + case VOCTRL_DRAW_IMAGE: + switch (image_format) { + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + //case IMGFMT_UYVY: + //case IMGFMT_YUY2: + return draw_yuv_image(data); + break; + } +#endif } return VO_NOTIMPL; } @@ -467,6 +961,41 @@ CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0); CGContextFillRect(context, winBounds); CGContextFlush(context); + + + switch (image_format) { +#ifdef QUARTZ_ENABLE_YUV + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + case IMGFMT_UYVY: + case IMGFMT_YUY2: + { + long scale_X = FixDiv(Long2Fix(dstRect.right - dstRect.left),Long2Fix(image_width)); + long scale_Y = FixDiv(Long2Fix(dstRect.bottom - dstRect.top),Long2Fix(image_height)); + + SetIdentityMatrix(&yuv_qt_stuff.matrix); + if (((dstRect.right - dstRect.left) != image_width) || + ((dstRect.bottom - dstRect.right) != image_height)) { + ScaleMatrix(&yuv_qt_stuff.matrix, + scale_X, + scale_Y, + 0, + 0); + + if (padding > 0) { + TranslateMatrix(&yuv_qt_stuff.matrix, + Long2Fix(dstRect.left), + Long2Fix(dstRect.top)); + } + } + SetDSequenceMatrix(yuv_qt_stuff.seqId, &yuv_qt_stuff.matrix); + break; + } +#endif + default: + break; + } } void window_ontop() @@ -509,7 +1038,7 @@ HideCursor(); //go fullscreen - ChangeWindowAttributes(theWindow, 0, kWindowResizableAttribute); + //ChangeWindowAttributes(theWindow, 0, kWindowResizableAttribute); MoveWindow (theWindow, 0, 0, 1); SizeWindow(theWindow, device_width, device_height,1); @@ -531,7 +1060,7 @@ ShowCursor(); //revert window to previous setting - ChangeWindowAttributes(theWindow, kWindowResizableAttribute, 0); + //ChangeWindowAttributes(theWindow, kWindowResizableAttribute, 0); SizeWindow(theWindow, oldRect.right, oldRect.bottom,1); RepositionWindow(theWindow, NULL, kWindowCascadeOnMainScreen); Index: DOCS/man/en/mplayer.1 =================================================================== RCS file: /cvsroot/mplayer/main/DOCS/man/en/mplayer.1,v retrieving revision 1.579 diff -u -r1.579 mplayer.1 --- DOCS/man/en/mplayer.1 28 Apr 2004 04:55:04 -0000 1.579 +++ DOCS/man/en/mplayer.1 30 Apr 2004 12:06:41 -0000 @@ -3655,6 +3655,30 @@ .TP .B quartz (Mac OS X only) Mac OS X Quartz output driver. +.PD 0 +.RSs +.IPs use_rgb +Force use of mode: packed 32bits RGB +.IPs use_yv12 +Force use of mode: planar YUV +.IPs use_iyuv +Force use of mode: planar YUV (same as use_yv12) +.IPs use_i420 +Force use of mode: planar YUV (same as use_yv12) +.IPs use_y420 +Force use of mode: planar YUV (same as use_yv12) +.IPs use_myuv +Force use of mode: planar YUV (same as use_yv12) +.IPs use_yuy2 +Force use of mode: packed YUV CbCr Y' 4:2:2 +.IPs use_yuvs +Force use of mode: packed YUV (same as use_yuy2) +.IPs use_uyvy +Force use of mode: packed YUV Y'CbCr 8-bit 4:2:2 +.IPs use_2vuy +Force use of mode: packed YUV (same as use_uyvy) +.RE +.PD 1 .TP .B fbdev (Linux only) Uses the kernel framebuffer to output video.