Initial import of Scalos. To decrease size I have
[AROS-Contrib.git] / scalos / Plugins / Preview / Video / Video.c
blob01f3aa9bea63df09931ccbd3185b2b961b226163
1 // Video.c
2 // $Date$
3 // $Revision$
5 #include <exec/types.h>
6 #include <exec/libraries.h>
7 #include <exec/execbase.h>
8 #include <exec/lists.h>
9 #include <graphics/gfxbase.h>
10 #include <scalos/scalos.h>
11 #include <scalos/scalosgfx.h>
12 #include <datatypes/pictureclass.h>
13 #include <scalos/scalospreviewplugin.h>
14 #include <cybergraphx/cybergraphics.h>
15 #include <utility/hooks.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <ctype.h>
21 #include <limits.h>
22 #include <stdio.h>
24 #include <clib/alib_protos.h>
26 #include <proto/dos.h>
27 #include <proto/exec.h>
28 #include <proto/utility.h>
29 #include <proto/scalosgfx.h>
30 #include <proto/graphics.h>
31 #include <proto/intuition.h>
33 #include <defs.h>
35 #undef GLOBAL
37 #include <libavcodec/avcodec.h>
38 #include <libavcodec/imgconvert.h>
39 #include <avformat.h>
40 #include <swscale.h>
42 #include "Video.h"
44 //---------------------------------------------------------------------------------------
46 // set BYTEDUMP to 1 if you need to use ByteDump()
47 #define BYTEDUMP 0
49 #if 1
50 #define DUMP_ARGB_LINE(argbh, component, yy)
51 #else
52 #define DUMP_ARGB_LINE(argbh, component, yy) \
53 { \
54 int n; \
55 const struct ARGB *argb = &(argbh)->argb_ImageData[(yy) * (argbh)->argb_Width]; \
56 KPrintF(__FILE__ "/%s/%ld: w=%ld h=%ld yy=%ld #component:\n", __FUNC__, __LINE__, \
57 (argbh)->argb_Width, (argbh)->argb_Height, yy); \
58 KPrintF(__FILE__ "/%s/%ld: ", __FUNC__, __LINE__); \
59 for (n = 0; n < (argbh)->argb_Width; n++, argb++) \
60 { \
61 if (n > 0 && 0 == n % 16) \
62 KPrintF("\n" __FILE__ "/%s/%ld: ", __FUNC__, __LINE__); \
63 KPrintF("%02lx ", argb->component); \
64 } \
65 KPrintF("\n"); \
67 #endif
69 //---------------------------------------------------------------------------------------
71 #define NO_STREAM -1
73 struct AVInfo
75 int avinf_VideoStream;
76 AVFormatContext *avinf_pFormatContext;
77 AVCodecContext *avinf_pCodecContext;
78 AVCodec *avinf_pVideoCodec;
79 AVStream *avinf_pVideoStream;
80 AVFrame *avinf_pFrame; // Video frame in native format
81 AVFrame *avinf_pRGBFrame; // Converted Video frame in RGB format
82 UBYTE *avinf_Buffer; // Buffer for RGB image data
83 BOOL avinf_CodecOpened; // Flag: av_codec_open() succeeded
86 struct VideoFrame
88 int vfr_width;
89 int vfr_height;
90 int vfr_lineSize;
93 //---------------------------------------------------------------------------------------
95 struct GfxBase *GfxBase;
96 T_UTILITYBASE UtilityBase;
97 struct Library *CyberGfxBase;
98 struct DosLibrary *DOSBase;
99 struct IntuitionBase *IntuitionBase;
100 struct ScalosGfxBase *ScalosGfxBase;
102 #ifdef __amigaos4__
103 struct Library *NewlibBase;
104 struct Interface *INewlib;
105 struct GraphicsIFace *IGraphics;
106 struct UtilityIFace *IUtility;
107 struct ExecIFace *IExec;
108 struct CyberGfxIFace *ICyberGfx;
109 struct DOSIFace *IDOS;
110 struct IntuitionIFace *IIntuition;
111 struct ScalosGfxIFace *IScalosGfx;
112 #endif /* __amigaos4__ */
114 /* won't compile for me when defined as constants - mazze */
115 #define FILMHOLE_WIDTH (12)
116 #define FILMHOLE_HEIGHT (10)
118 STRPTR VersTag = LIB_VERSTRING;
120 //---------------------------------------------------------------------------------------
122 static BOOL GenerateRemappedThumbnail(struct ScaWindowTask *wt,
123 CONST_STRPTR iconName,
124 struct AVInfo *avInfo, struct VideoFrame *vFrame,
125 ULONG quality, ULONG SupportedColors, ULONG ReservedColors,
126 ULONG ScaledWidth, ULONG ScaledHeight,
127 struct Screen *WBScreen, struct ScalosPreviewResult *PVResult);
128 static BOOL GenerateARGBThumbnail(struct ScaWindowTask *wt,
129 CONST_STRPTR iconName,
130 struct AVInfo *avInfo, struct VideoFrame *vFrame,
131 ULONG quality,
132 ULONG ScaledWidth, ULONG ScaledHeight,
133 struct ScalosPreviewResult *PVResult);
134 static void CleanupAVInfo(struct AVInfo *avInfo);
135 static BOOL InitializeVideo(struct AVInfo *avInfo);
136 static BOOL ReadVideoFrame(struct AVInfo *avInfo);
137 static BOOL GetScaledVideoFrame(struct AVInfo *avInfo, int scaledSize,
138 ULONG quality, struct VideoFrame *videoFrame);
139 static BOOL ConvertAndScaleFrame(struct AVInfo *avInfo, int format, int scaledSize,
140 int *scaledWidth, int *scaledHeight, ULONG quality);
141 static void CalculateDimensions(int srcWidth, int srcHeight, int squareSize, int *destWidth, int *destHeight);
142 static BOOL AllocFrameData(AVFrame **avFrame, int width, int height, int format);
143 static BOOL VideoSeekFrame(struct AVInfo *avInfo, float timeInSeconds);
144 static void OverlayFilmStrip(struct AVInfo *avInfo, struct VideoFrame *videoFrame);
145 static BOOL IsInterestingFrame(const struct AVInfo *avInfo);
146 static BOOL FindInterestingFrame(struct AVInfo *avInfo);
147 static void av_log_dummy_callback(void* ptr, int level, const char* fmt, va_list vl);
149 #if BYTEDUMP
150 static void ByteDump(const unsigned char *Data, size_t Length);
151 #endif /* BYTEDUMP */
153 //-----------------------------------------------------------
155 BOOL initPlugin(struct PluginBase *PluginBase)
157 BOOL result = FALSE;
159 d1(KPrintF("%s/%s/%ld: PluginBase=%08lx procName=<%s>\n", __FILE__, __FUNC__, __LINE__, \
160 PluginBase, FindTask(NULL)->tc_Node.ln_Name));
162 do {
163 #ifndef __amigaos4__
164 if (_STI_240_InitMemFunctions())
165 break;
166 #endif /* __amigaos4__ */
167 DOSBase = (APTR) OpenLibrary( "dos.library", 39 );
168 if (NULL == DOSBase)
169 break;
171 UtilityBase = (T_UTILITYBASE) OpenLibrary("utility.library", 39);
172 if (NULL == UtilityBase)
173 break;
175 CyberGfxBase = OpenLibrary(CYBERGFXNAME, 0);
176 // CyberGfxBase may be NULL
178 IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 39);
179 d1(kprintf("%s/%s/%ld: IntuitionBase=%08lx\n", __FILE__, __FUNC__, __LINE__, IntuitionBase));
180 if (NULL == IntuitionBase)
181 break;
183 GfxBase = (struct GfxBase *) OpenLibrary(GRAPHICSNAME, 39);
184 d1(kprintf("%s/%s/%ld: GfxBase=%08lx\n", __FILE__, __FUNC__, __LINE__, GfxBase));
185 if (NULL == GfxBase)
186 break;
188 ScalosGfxBase = (struct ScalosGfxBase *) OpenLibrary(SCALOSGFXNAME, 41);
189 d1(KPrintF("%s/%s/%ld: ScalosGfxBase=%08lx\n", __FILE__, __FUNC__, __LINE__, ScalosGfxBase));
190 if (NULL == ScalosGfxBase)
191 break;
193 #ifdef __amigaos4__
194 IDOS = (struct DOSIFace *) GetInterface((struct Library *)DOSBase, "main", 1, NULL);
195 if (IDOS == NULL)
196 break;
197 if (CyberGfxBase != NULL) // CyberGfxBase may be NULL
199 ICyberGfx = (struct CyberGfxIFace *) GetInterface((struct Library *) CyberGfxBase, "main", 1, NULL);
200 if (ICyberGfx == NULL)
201 break;
203 IUtility = (struct UtilityIFace *) GetInterface((struct Library *) UtilityBase, "main", 1, NULL);
204 if (NULL == IUtility)
205 break;
206 IIntuition = (struct IntuitionIFace *) GetInterface((struct Library *) IntuitionBase, "main", 1, NULL);
207 if (NULL == IIntuition)
208 break;
209 IGraphics = (struct GraphicsIFace *) GetInterface((struct Library *) GfxBase, "main", 1, NULL);
210 if (NULL == IGraphics)
211 break;
212 IScalosGfx = (struct ScalosGfxIFace *) GetInterface((struct Library *) ScalosGfxBase, "main", 1, NULL);
213 if (NULL == IScalosGfx)
214 break;
215 NewlibBase = OpenLibrary("newlib.library", 0);
216 if (NULL == NewlibBase)
217 break;
218 INewlib = GetInterface(NewlibBase, "main", 1, NULL);
219 if (NULL == INewlib)
220 break;
221 #endif /* __amigaos4__ */
223 if (!InitExtra())
224 break;
226 av_register_all();
228 result = TRUE;
229 d1(KPrintF("%s/%s/%ld: Success\n", __FILE__, __FUNC__, __LINE__));
230 } while (0);
232 return result;
236 void closePlugin(struct PluginBase *PluginBase)
238 d1(kprintf("%s/%s/%ld:\n", __FILE__, __FUNC__, __LINE__));
240 ExitExtra();
242 #ifndef __amigaos4__
243 _STD_240_TerminateMemFunctions();
244 #endif
246 #ifdef __amigaos4__
247 if (INewlib)
249 DropInterface(INewlib);
250 INewlib = NULL;
252 if (NewlibBase)
254 CloseLibrary(NewlibBase);
255 NewlibBase = NULL;
257 if (ICyberGfx)
259 DropInterface((struct Interface *)ICyberGfx);
260 ICyberGfx = NULL;
262 if (IScalosGfx)
264 DropInterface((struct Interface *)IScalosGfx);
265 IScalosGfx = NULL;
267 if (IGraphics)
269 DropInterface((struct Interface *)IGraphics);
270 IGraphics = NULL;
272 if (IIntuition)
274 DropInterface((struct Interface *)IIntuition);
275 IIntuition = NULL;
277 if (IUtility)
279 DropInterface((struct Interface *)IUtility);
280 IUtility = NULL;
282 if (IDOS)
284 DropInterface((struct Interface *)IDOS);
285 IDOS = NULL;
287 #endif /* __amigaos4__ */
289 if (CyberGfxBase)
291 CloseLibrary(CyberGfxBase);
292 CyberGfxBase = NULL;
294 if (NULL != ScalosGfxBase)
296 CloseLibrary((struct Library *) ScalosGfxBase);
297 ScalosGfxBase = NULL;
299 if (NULL != GfxBase)
301 CloseLibrary((struct Library *) GfxBase);
302 GfxBase = NULL;
304 if (NULL != IntuitionBase)
306 CloseLibrary((struct Library *) IntuitionBase);
307 IntuitionBase = NULL;
310 if (NULL != UtilityBase)
312 CloseLibrary((struct Library *) UtilityBase);
313 UtilityBase = NULL;
315 if (NULL != DOSBase)
317 CloseLibrary((struct Library *) DOSBase);
318 DOSBase = NULL;
322 //--------------------------------------------------------------------------
324 LIBFUNC_P5(LONG, LIBSCAPreviewGenerate,
325 A0, struct ScaWindowTask *, wt,
326 A1, BPTR, dirLock,
327 A2, CONST_STRPTR, iconName,
328 A3, struct TagItem *, tagList,
329 A6, struct PluginBase *, PluginBase)
331 LONG Success = FALSE;
333 (void) PluginBase;
335 if (InitInstance())
337 BPTR oldDir = (BPTR)NULL;
338 struct AVInfo avInfo;
339 struct VideoFrame vFrame;
341 memset(&vFrame, 0, sizeof(struct VideoFrame));
343 d1(KPrintF("%s/%s/%ld: START iconName=<%s>\n", __FILE__, __FUNC__, __LINE__, iconName));
345 do {
346 ULONG ThumbnailWidth;
347 ULONG ThumbnailHeight;
348 ULONG SupportedColors;
349 ULONG ScreenDepth;
350 struct Screen *WBScreen;
351 struct BitMapHeader *bmhdExternal;
352 struct ScalosPreviewResult *PVResult;
353 BOOL DoRemap;
354 ULONG quality;
355 ULONG ReservedColors;
356 int rc;
358 memset(&avInfo, 0, sizeof(struct AVInfo));
360 av_log_set_callback(av_log_dummy_callback);
362 d1(KPrintF("%s/%s/%ld: after av_log_set_callback\n", __FILE__, __FUNC__, __LINE__));
364 PVResult = (struct ScalosPreviewResult *) GetTagData(SCALOSPREVIEW_ResultStruct, (ULONG)NULL, tagList);
365 if (NULL == PVResult)
366 break;
368 // clear result
369 memset(PVResult, 0, sizeof(*PVResult));
371 ThumbnailWidth = GetTagData(SCALOSPREVIEW_ThumbnailWidth, 0, tagList);
372 if (0 == ThumbnailWidth)
373 break;
374 ThumbnailHeight = GetTagData(SCALOSPREVIEW_ThumbnailHeight, 0, tagList);
375 if (0 == ThumbnailHeight)
376 break;
378 SupportedColors = GetTagData(SCALOSPREVIEW_SupportedColors, 0, tagList);
379 if (SupportedColors < 16)
380 break;
382 ReservedColors = GetTagData(SCALOSPREVIEW_ReservedColors, 0, tagList);
383 if (SupportedColors < ReservedColors + 16)
384 break;
386 bmhdExternal = (struct BitMapHeader *) GetTagData(SCALOSPREVIEW_ImgBitMapHeader, (ULONG)NULL, tagList);
387 quality = GetTagData(SCALOSPREVIEW_Quality, SCALOSPREVIEWA_Quality_Max, tagList);
389 WBScreen = (struct Screen *) GetTagData(SCALOSPREVIEW_Screen, (ULONG)NULL, tagList);
390 if (NULL == WBScreen)
391 break;
393 oldDir = CurrentDir(dirLock);
395 d1(KPrintF("%s/%s/%ld: before av_open_input_file\n", __FILE__, __FUNC__, __LINE__));
397 // Open video file
398 rc = av_open_input_file(&avInfo.avinf_pFormatContext, iconName, NULL, 0, NULL);
399 d1(KPrintF("%s/%s/%ld: rc=%d\n", __FILE__, __FUNC__, __LINE__, rc));
400 if (0 != rc)
402 d1(KPrintF("%s/%s/%ld: av_open_input_file failed\n", __FILE__, __FUNC__, __LINE__));
403 break;
406 d1(KPrintF("%s/%s/%ld: before InitializeVideo\n", __FILE__, __FUNC__, __LINE__));
408 if (!InitializeVideo(&avInfo))
409 break;
411 d1(KPrintF("%s/%s/%ld: after InitializeVideo\n", __FILE__, __FUNC__, __LINE__));
413 if (!ReadVideoFrame(&avInfo)) //before seeking, a frame has to be decoded
414 break;
416 d1(KPrintF(__FILE__ "%s/%s/%ld: ReadVideoFrame success\n", __FILE__, __FUNC__, __LINE__));
418 if (bmhdExternal)
420 #if 1
421 bmhdExternal->bmh_Width = avInfo.avinf_pCodecContext->width;
422 bmhdExternal->bmh_Height = avInfo.avinf_pCodecContext->height;
423 #else
424 bmhdExternal->bmh_Width = 2;
425 bmhdExternal->bmh_Height = 2;
426 #endif
427 bmhdExternal->bmh_Depth = 24;
430 if (!FindInterestingFrame(&avInfo))
431 break;
433 if (!GetScaledVideoFrame(&avInfo, ThumbnailWidth, quality, &vFrame))
434 break;
436 d1(KPrintF("%s/%s/%ld: vfr_width=%ld vfr_height=%ld vfr_lineSize=%ld\n", __FILE__, __FUNC__, __LINE__, vFrame.vfr_width, vFrame.vfr_height, vFrame.vfr_lineSize));
438 if (vFrame.vfr_width > FILMHOLE_WIDTH * 2)
440 OverlayFilmStrip(&avInfo, &vFrame);
443 ScreenDepth = GetBitMapAttr(WBScreen->RastPort.BitMap, BMA_DEPTH);
445 DoRemap = (ScreenDepth <= 8) || (NULL == CyberGfxBase) || SupportedColors <= 256;
447 d1(KPrintF("%s/%s/%ld: DoRemap=%ld\n", __FILE__, __FUNC__, __LINE__, DoRemap));
449 if (DoRemap)
451 d1(KPrintF("%s/%s/%ld: SupportedColors=%lu ReservedColors=%ld\n", \
452 __FILE__, __FUNC__, __LINE__, SupportedColors, ReservedColors));
454 Success = GenerateRemappedThumbnail(wt,
455 iconName,
456 &avInfo, &vFrame,
457 quality, SupportedColors, ReservedColors,
458 ThumbnailWidth, ThumbnailHeight,
459 WBScreen, PVResult);
461 else
463 Success = GenerateARGBThumbnail(wt,
464 iconName,
465 &avInfo, &vFrame,
466 quality,
467 ThumbnailWidth, ThumbnailHeight,
468 PVResult);
470 } while (0);
472 d1(KPrintF("%s/%s/%ld: \n", __FILE__, __FUNC__, __LINE__));
474 if (oldDir)
475 CurrentDir(oldDir);
477 CleanupAVInfo(&avInfo);
479 ExitInstance();
482 d1(KPrintF("%s/%s/%ld: END Success=%ld\n", __FILE__, __FUNC__, __LINE__, Success));
484 return Success;
486 LIBFUNC_END
488 //----------------------------------------------------------------------------
490 #ifndef __amigaos4__
491 void _XCEXIT(long x)
495 //----------------------------------------------------------------------------
497 #ifndef __SASC
498 // Replacement for SAS/C library functions
500 void exit(int x)
502 (void) x;
503 while (1)
507 APTR _WBenchMsg;
509 #endif /* __SASC */
511 #endif /* __amigaos4__ */
513 //-----------------------------------------------------------------------------
515 static BOOL GenerateRemappedThumbnail(struct ScaWindowTask *wt,
516 CONST_STRPTR iconName,
517 struct AVInfo *avInfo, struct VideoFrame *vFrame,
518 ULONG quality, ULONG SupportedColors, ULONG ReservedColors,
519 ULONG ScaledWidth, ULONG ScaledHeight,
520 struct Screen *WBScreen, struct ScalosPreviewResult *PVResult)
522 BOOL Success = FALSE;
523 struct ARGBHeader argbTemp = { 0, 0, NULL };
524 struct ScalosBitMapAndColor *sacSrc = NULL;
525 struct ScalosBitMapAndColor *sacDest = NULL;
526 struct BitMap *TempBM = NULL;
528 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
530 do {
531 struct ARGB *pLine;
532 const UBYTE *src;
533 ULONG Depth;
534 ULONG y;
536 argbTemp.argb_Width = vFrame->vfr_width;
537 argbTemp.argb_Height = vFrame->vfr_height;
538 argbTemp.argb_ImageData = ScalosGfxCreateARGB(argbTemp.argb_Width, argbTemp.argb_Height, NULL);
539 d1(KPrintF("%s/%s/%ld: argb_ImageData=%08lx\n", __FILE__, __FUNC__, __LINE__, argbTemp.argb_ImageData));
540 if (NULL == argbTemp.argb_ImageData)
541 break;
543 // Fill argbSrc with image from vFrame
544 pLine = argbTemp.argb_ImageData;
545 src = avInfo->avinf_pFrame->data[0];
546 for (y = 0; y < vFrame->vfr_height; y++)
548 ULONG x;
550 for (x = 0; x < vFrame->vfr_width; x++)
552 pLine->Red = *src++;
553 pLine->Green = *src++;
554 pLine->Blue = *src++;
555 pLine->Alpha = (UBYTE) ~0;
557 pLine++;
561 // Limit color depth to the number of colors supported by the icon
562 for (Depth = 0; Depth < 7 && (1 << Depth) < SupportedColors; Depth++)
565 d1(KPrintF(__FILE__ "/%s/%ld: argb_ImageData: a=%ld r=%ld g=%ld b=%ld\n", \
566 __FUNC__, __LINE__, argbTemp.argb_ImageData->Alpha, \
567 argbTemp.argb_ImageData->Red, argbTemp.argb_ImageData->Green, \
568 argbTemp.argb_ImageData->Blue));
570 d1(KPrintF(__FILE__ "/%s/%ld: SupportedColors=%lu Depth=%lu ReservedColors=%lu\n", \
571 __FUNC__, __LINE__, SupportedColors, Depth, ReservedColors));
573 PVResult->spvr_sac = ScalosGfxMedianCutTags(&argbTemp, Depth,
574 SCALOSGFX_MedianCutFlags, SCALOSGFXFLAGF_MedianCut_FloydSteinberg,
575 SCALOSGFX_MedianCutFriendBitMap, NULL,
576 SCALOSGFX_MedianCutReservedColors, ReservedColors,
577 TAG_END);
578 d1(KPrintF(__FILE__ "/%s/%ld: sac=%08lx\n", __FUNC__, __LINE__, PVResult->spvr_sac));
580 d1(KPrintF(__FILE__ "/%s/%ld: sac_BitMap=%08lx\n", __FUNC__, __LINE__, PVResult->spvr_sac->sac_BitMap));
581 d1(ByteDump((unsigned char *) PVResult->spvr_sac->sac_BitMap, sizeof(struct BitMap)));
583 Success = TRUE;
584 } while (0);
586 if (TempBM)
587 FreeBitMap(TempBM);
589 ScalosGfxFreeARGB(&argbTemp.argb_ImageData);
590 ScalosGfxFreeSAC(sacSrc);
591 ScalosGfxFreeSAC(sacDest);
593 d1(KPrintF("%s/%s/%ld: END Success=%08lx\n", __FILE__, __FUNC__, __LINE__, Success));
595 return Success;
598 //-----------------------------------------------------------------------------
600 static BOOL GenerateARGBThumbnail(struct ScaWindowTask *wt,
601 CONST_STRPTR iconName,
602 struct AVInfo *avInfo, struct VideoFrame *vFrame,
603 ULONG quality,
604 ULONG ScaledWidth, ULONG ScaledHeight,
605 struct ScalosPreviewResult *PVResult)
607 BOOL Success = FALSE;
608 struct ARGBHeader argbSrc = { 0, 0, NULL };
610 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
612 do {
613 struct ARGB *pLine;
614 const UBYTE *src;
615 ULONG y;
617 argbSrc.argb_Width = vFrame->vfr_width;
618 argbSrc.argb_Height = vFrame->vfr_height;
619 argbSrc.argb_ImageData = ScalosGfxCreateARGB(argbSrc.argb_Width, argbSrc.argb_Height, NULL);
620 d1(KPrintF("%s/%s/%ld: argb_ImageData=%08lx\n", __FILE__, __FUNC__, __LINE__, argbSrc.argb_ImageData));
621 if (NULL == argbSrc.argb_ImageData)
622 break;
624 // Fill argbSrc with image from vFrame
625 pLine = argbSrc.argb_ImageData;
626 src = avInfo->avinf_pFrame->data[0];
627 for (y = 0; y < vFrame->vfr_height; y++)
629 ULONG x;
631 for (x = 0; x < vFrame->vfr_width; x++)
633 pLine->Red = *src++;
634 pLine->Green = *src++;
635 pLine->Blue = *src++;
636 pLine->Alpha = (UBYTE) ~0;
638 pLine++;
642 PVResult->spvr_ARGBheader = argbSrc;
643 memset(&argbSrc, 0, sizeof(argbSrc));
645 Success = TRUE;
646 } while (0);
648 if (!Success)
649 ScalosGfxFreeARGB(&argbSrc.argb_ImageData);
651 d1(KPrintF("%s/%s/%ld: END Success=%ld\n", __FILE__, __FUNC__, __LINE__, Success));
653 return Success;
656 //-----------------------------------------------------------------------------
658 static void CleanupAVInfo(struct AVInfo *avInfo)
660 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
662 d1(KPrintF("%s/%s/%ld: avinf_pCodecContext=%08lx avinf_CodecOpened=%ld\n", __FILE__, __FUNC__, __LINE__, \
663 avInfo->avinf_pCodecContext, avInfo->avinf_CodecOpened));
664 if (avInfo->avinf_CodecOpened)
666 avcodec_close(avInfo->avinf_pCodecContext);
667 avInfo->avinf_pCodecContext = NULL;
668 avInfo->avinf_CodecOpened = FALSE;
670 d1(KPrintF("%s/%s/%ld: avinf_pFormatContext=%08lx\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pFormatContext));
671 if (avInfo->avinf_pFormatContext)
673 av_close_input_file(avInfo->avinf_pFormatContext);
674 avInfo->avinf_pFormatContext = NULL;
676 d1(KPrintF("%s/%s/%ld: avinf_pFrame=%08lx\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pFrame));
677 if (avInfo->avinf_pFrame)
679 av_free(avInfo->avinf_pFrame);
680 avInfo->avinf_pFrame = NULL;
682 d1(KPrintF("%s/%s/%ld: avinf_pRGBFrame=%08lx\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pRGBFrame));
683 if (avInfo->avinf_pRGBFrame)
685 av_free(avInfo->avinf_pRGBFrame);
686 avInfo->avinf_pRGBFrame = NULL;
688 d1(KPrintF("%s/%s/%ld: avinf_Buffer=%08lx\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_Buffer));
689 if (avInfo->avinf_Buffer)
691 free(avInfo->avinf_Buffer);
692 avInfo->avinf_Buffer = NULL;
694 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
697 //-----------------------------------------------------------------------------
699 static BOOL InitializeVideo(struct AVInfo *avInfo)
701 BOOL Success = FALSE;
703 do {
704 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
706 // Retrieve stream information
707 if (av_find_stream_info(avInfo->avinf_pFormatContext) < 0)
709 d1(KPrintF("%s/%s/%ld: av_find_stream_info failed\n", __FILE__, __FUNC__, __LINE__));
710 break;
713 d1(KPrintF("%s/%s/%ld: nb_streams=%ld\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pFormatContext->nb_streams));
714 if (avInfo->avinf_pFormatContext->nb_streams < 1)
716 d1(KPrintF("%s/%s/%ld: no streams found\n", __FILE__, __FUNC__, __LINE__));
717 break;
720 // Find the first video stream
721 avInfo->avinf_VideoStream = av_find_default_stream_index(avInfo->avinf_pFormatContext);
723 d1(KPrintF("%s/%s/%ld: avinf_VideoStream=%ld\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_VideoStream));
724 if (NO_STREAM == avInfo->avinf_VideoStream)
726 d1(KPrintF("%s/%s/%ld: Could not find video stream\n", __FILE__, __FUNC__, __LINE__));
727 break;
730 avInfo->avinf_pVideoStream = avInfo->avinf_pFormatContext->streams[avInfo->avinf_VideoStream];
732 // Remember pointer to codec context for the video stream
733 avInfo->avinf_pCodecContext = avInfo->avinf_pVideoStream->codec;
735 // Find decoder for the video stream
736 avInfo->avinf_pVideoCodec = avcodec_find_decoder(avInfo->avinf_pCodecContext->codec_id);
738 d1(KPrintF("%s/%s/%ld: avinf_pCodecContext=%08lx avinf_pVideoCodec=%08lx\n", \
739 __FILE__, __FUNC__, __LINE__, avInfo->avinf_pCodecContext, avInfo->avinf_pVideoCodec));
740 if (NULL == avInfo->avinf_pVideoCodec)
742 d1(KPrintF("%s/%s/%ld: Video Codec not found\n", __FILE__, __FUNC__, __LINE__));
743 break;
746 d1(KPrintF("%s/%s/%ld: Codec name=<%s>\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pVideoCodec->name));
748 avInfo->avinf_pCodecContext->workaround_bugs = 1;
749 avInfo->avinf_pFormatContext->flags |= AVFMT_FLAG_GENPTS;
750 if(avInfo->avinf_pVideoCodec->capabilities & CODEC_CAP_TRUNCATED)
751 avInfo->avinf_pCodecContext->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */
753 #if 1
754 d1(KPrintF("%s/%s/%ld: width=%ld height=%ld pix_fmt=%ld\n", __FILE__, __FUNC__, __LINE__, \
755 avInfo->avinf_pCodecContext->width, avInfo->avinf_pCodecContext->height, \
756 avInfo->avinf_pCodecContext->pix_fmt));
758 if (0 == avInfo->avinf_pCodecContext->width)
760 break;
762 #endif
763 // Open codec
764 if (avcodec_open(avInfo->avinf_pCodecContext, avInfo->avinf_pVideoCodec) < 0)
766 d1(KPrintF("%s/%s/%ld: avcodec_open failed\n", __FILE__, __FUNC__, __LINE__));
767 break;
769 avInfo->avinf_CodecOpened = TRUE;
771 // Allocate video frame
772 avInfo->avinf_pFrame = avcodec_alloc_frame();
773 d1(KPrintF("%s/%s/%ld: avinf_pFrame=%08lx\n", __FILE__, __FUNC__, __LINE__, avInfo->avinf_pFrame));
774 if (NULL == avInfo->avinf_pFrame)
775 break;
777 if (!AllocFrameData(&avInfo->avinf_pRGBFrame,
778 avInfo->avinf_pCodecContext->width,
779 avInfo->avinf_pCodecContext->height,
780 PIX_FMT_RGB24))
782 break;
785 Success = TRUE;
786 } while (0);
788 d1(KPrintF("%s/%s/%ld: END Success=%ld\n", __FILE__, __FUNC__, __LINE__, Success));
790 return Success;
793 //-----------------------------------------------------------------------------
795 static BOOL ReadVideoFrame(struct AVInfo *avInfo)
797 AVPacket packet;
798 int frameFinished = FALSE;
799 ULONG Tries = 0;
801 d1(KPrintF("%s/%s/%ld: START\n", __FILE__, __FUNC__, __LINE__));
803 av_init_packet(&packet);
805 while (av_read_frame(avInfo->avinf_pFormatContext, &packet) >= 0)
807 // Is this a packet from the video stream?
808 if (packet.stream_index == avInfo->avinf_VideoStream)
810 int size = packet.size;
811 UBYTE *buffer = packet.data;
813 while ((size > 0) && !frameFinished)
815 int bytesDecoded;
817 bytesDecoded = avcodec_decode_video(avInfo->avinf_pCodecContext,
818 avInfo->avinf_pFrame,
819 &frameFinished,
820 buffer,
821 size);
823 d1(KPrintF("%s/%s/%ld: packet.size=%d frameFinished=%ld bytesDecoded=%ld\n", \
824 __FILE__, __FUNC__, __LINE__, packet.size, frameFinished, bytesDecoded));
825 d1(KPrintF("%s/%s/%ld: pix_fmt=%d width=%ld height=%ld\n", \
826 __FILE__, __FUNC__, __LINE__, avInfo->avinf_pCodecContext->pix_fmt, \
827 avInfo->avinf_pCodecContext->width, avInfo->avinf_pCodecContext->height));
829 if (bytesDecoded < 0)
830 break; // failure
832 if (frameFinished && (bytesDecoded >= 0))
834 struct SwsContext *ImgConvertContext;
835 int rc;
837 d1( { \
838 char buffer[80]; \
839 sprintf(buffer, "pts=%llu dts=%llu", packet.pts, packet.dts);
840 KPrintF("%s/%s/%ld: %s\n", __FILE__, __FUNC__, __LINE__, buffer); \
841 } );
843 // Convert frame image from native format to RGB
844 ImgConvertContext = sws_getContext(avInfo->avinf_pCodecContext->width,
845 avInfo->avinf_pCodecContext->height,
846 avInfo->avinf_pCodecContext->pix_fmt,
847 avInfo->avinf_pCodecContext->width,
848 avInfo->avinf_pCodecContext->height,
849 PIX_FMT_RGB24,
850 SWS_FAST_BILINEAR,
851 NULL,
852 NULL,
853 NULL);
855 if (NULL == ImgConvertContext)
856 break;
858 rc = sws_scale(ImgConvertContext,
859 avInfo->avinf_pFrame->data,
860 avInfo->avinf_pFrame->linesize,
862 avInfo->avinf_pCodecContext->height,
863 avInfo->avinf_pRGBFrame->data,
864 avInfo->avinf_pRGBFrame->linesize);
866 d1(KPrintF("%s/%s/%ld: \n", __FILE__, __FUNC__, __LINE__));
868 sws_freeContext(ImgConvertContext);
870 if (-1 == rc)
871 break; // failure
872 break;
875 buffer += bytesDecoded;
876 size -= bytesDecoded;
878 if (Tries++ > 1000)
879 break;
883 av_free_packet(&packet);
885 if (Tries++ > 1000)
886 break;
889 d1(KPrintF("%s/%s/%ld: frameFinished=%ld\n", __FILE__, __FUNC__, __LINE__, frameFinished));
891 av_free_packet(&packet);
893 d1(KPrintF("%s/%s/%ld: END\n", __FILE__, __FUNC__, __LINE__));
895 return (BOOL) frameFinished;
898 //-----------------------------------------------------------------------------
900 static BOOL GetScaledVideoFrame(struct AVInfo *avInfo, int scaledSize,
901 ULONG quality, struct VideoFrame *videoFrame)
903 BOOL Success = FALSE;
905 do {
906 int scaledWidth, scaledHeight;
908 if (!ConvertAndScaleFrame(avInfo, PIX_FMT_RGB24, scaledSize,
909 &scaledWidth, &scaledHeight, quality))
910 break;
912 d1(KPrintF("%s/%s/%ld: ConvertAndScaleFrame success\n", __FILE__, __FUNC__, __LINE__));
914 videoFrame->vfr_width = scaledWidth;
915 videoFrame->vfr_height = scaledHeight;
916 videoFrame->vfr_lineSize = avInfo->avinf_pFrame->linesize[0];
918 d1(KPrintF("%s/%s/%ld: vfr_width=%ld vfr_height=%ld vfr_lineSize=%ld\n", __FILE__, __FUNC__, __LINE__, \
919 videoFrame->vfr_width, videoFrame->vfr_height, videoFrame->vfr_lineSize));
921 Success = TRUE;
922 } while (0);
924 return Success;
927 //-----------------------------------------------------------------------------
929 static BOOL ConvertAndScaleFrame(struct AVInfo *avInfo, int pixFormat,
930 int scaledSize, int *scaledWidth, int *scaledHeight, ULONG quality)
932 AVFrame *convertedFrame = NULL;
933 struct SwsContext *scaleContext;
934 BOOL Success = FALSE;
936 do {
937 int ScaleFlags;
939 if (quality > 10)
940 ScaleFlags = SWS_BICUBIC;
941 else if (quality > 5)
942 ScaleFlags = SWS_BILINEAR;
943 else
944 ScaleFlags = SWS_FAST_BILINEAR;
946 CalculateDimensions(avInfo->avinf_pCodecContext->width,
947 avInfo->avinf_pCodecContext->height,
948 scaledSize,
949 scaledWidth,
950 scaledHeight);
951 d1(KPrintF("%s/%s/%ld: width=%ld height=%ld\n", __FILE__, __FUNC__, __LINE__,
952 avInfo->avinf_pCodecContext->width, avInfo->avinf_pCodecContext->height));
953 d1(KPrintF("%s/%s/%ld: scaledWidth=%ld scaledHeight=%ld\n", \
954 __FILE__, __FUNC__, __LINE__, *scaledWidth, *scaledHeight));
956 d1({ \
957 ULONG n; \
958 const UBYTE *p = avInfo->avinf_pFrame->data[0]; \
960 for (n = 0; n < avInfo->avinf_pCodecContext->height; n++) \
962 ByteDump(p, avInfo->avinf_pFrame->linesize[0]); \
963 p += avInfo->avinf_pFrame->linesize[0]; \
967 scaleContext = sws_getContext(avInfo->avinf_pCodecContext->width,
968 avInfo->avinf_pCodecContext->height,
969 avInfo->avinf_pCodecContext->pix_fmt,
970 *scaledWidth,
971 *scaledHeight,
972 pixFormat,
973 ScaleFlags,
974 NULL,
975 NULL,
976 NULL);
978 d1(KPrintF("%s/%s/%ld: scaleContext=%08lx\n", __FILE__, __FUNC__, __LINE__, scaleContext));
979 if (NULL == scaleContext)
980 break;
982 if (!AllocFrameData(&convertedFrame, *scaledWidth, *scaledHeight, pixFormat))
983 break;
985 d1(KPrintF("%s/%s/%ld: convertedFrame=%08lx\n", __FILE__, __FUNC__, __LINE__, convertedFrame));
986 if (NULL == convertedFrame)
987 break;
989 sws_scale(scaleContext,
990 avInfo->avinf_pFrame->data,
991 avInfo->avinf_pFrame->linesize,
993 avInfo->avinf_pCodecContext->height,
994 convertedFrame->data,
995 convertedFrame->linesize);
997 Success = TRUE;
998 } while (0);
1000 if (scaleContext)
1001 sws_freeContext(scaleContext);
1003 if (Success)
1005 av_free(avInfo->avinf_pFrame);
1006 avInfo->avinf_pFrame = convertedFrame;
1009 return Success;
1012 //-----------------------------------------------------------------------------
1014 static void CalculateDimensions(int srcWidth, int srcHeight, int squareSize, int *destWidth, int *destHeight)
1016 if (srcWidth > srcHeight)
1018 *destWidth = squareSize;
1019 *destHeight = (int) ((float)(squareSize) / srcWidth * srcHeight);
1021 else
1023 *destWidth = (int)((float)(squareSize) / srcHeight * srcWidth);
1024 *destHeight = squareSize;
1028 //-----------------------------------------------------------------------------
1030 static BOOL AllocFrameData(AVFrame **avFrame, int width, int height, int pixFormat)
1032 int numBytes;
1034 *avFrame = avcodec_alloc_frame();
1035 d1(KPrintF("%s/%s/%ld: *avFrame=%08lx\n", __FILE__, __FUNC__, __LINE__, *avFrame));
1036 if (NULL == *avFrame)
1037 return FALSE;
1039 numBytes = avpicture_get_size(pixFormat, width, height);
1040 d1(KPrintF("%s/%s/%ld: numBytes=%ld\n", __FILE__, __FUNC__, __LINE__, numBytes));
1042 if (0 != avpicture_alloc((AVPicture *) *avFrame, pixFormat, width, height))
1044 d1(KPrintF("%s/%s/%ld: avpicture_alloc failed\n", __FILE__, __FUNC__, __LINE__));
1045 return FALSE;
1048 return TRUE;
1051 //-----------------------------------------------------------------------------
1053 static BOOL VideoSeekFrame(struct AVInfo *avInfo, float timeInSeconds)
1055 int rc;
1056 // int64_t timestamp = (int64_t) (10 * AV_TIME_BASE * timeInSeconds);
1057 int64_t timestamp = (int64_t) (AV_TIME_BASE * timeInSeconds);
1059 do {
1060 int count = 0;
1061 BOOL foundFrame;
1063 d1( { \
1064 char buffer[40]; \
1065 sprintf(buffer, "timeInSeconds=%f timestamp=%llu", timeInSeconds, timestamp); \
1066 KPrintF("%s/%s/%ld: %s\n", __FILE__, __FUNC__, __LINE__, buffer); \
1067 } );
1069 rc = av_seek_frame(avInfo->avinf_pFormatContext, -1, timestamp, 0);
1070 d1(KPrintF("%s/%s/%ld: rc=%ld\n", __FILE__, __FUNC__, __LINE__, rc));
1071 if (rc < 0)
1072 break;
1074 do {
1075 foundFrame = ReadVideoFrame(avInfo);
1077 d1(KPrintF("%s/%s/%ld: foundFrame=%ld count=%ld\n", __FILE__, __FUNC__, __LINE__, foundFrame, ++count));
1078 } while (!foundFrame /* && !avInfo->avinf_pFrame->key_frame */ && ++count < 20);
1080 d1( { \
1081 char buffer[80]; \
1083 sprintf(buffer, "pts=%f coded_picture_number=%d display_picture_number=%d", \
1084 (float) (avInfo->avinf_pFrame->pts * avInfo->avinf_pCodecContext->time_base.num) \
1085 / (float) avInfo->avinf_pCodecContext->time_base.den, \
1086 avInfo->avinf_pFrame->coded_picture_number, \
1087 avInfo->avinf_pFrame->display_picture_number); \
1088 KPrintF("%s/%s/%ld: %s\n", __FILE__, __FUNC__, __LINE__, buffer); \
1089 } );
1090 } while (0);
1092 return TRUE;
1095 //-----------------------------------------------------------------------------
1097 static void OverlayFilmStrip(struct AVInfo *avInfo, struct VideoFrame *videoFrame)
1099 static const UBYTE filmHole[FILMHOLE_WIDTH * FILMHOLE_HEIGHT * 3] =
1101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x23, 0x7a, 0x7a, 0x7a, 0x83, 0x83, 0x83, 0x8c, 0x8c, 0x8c, 0x90, 0x90, 0x90, 0x8e, 0x8e, 0x8e, 0x52, 0x52, 0x52, 0x00, 0x00, 0x00,
1105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x6e, 0x6e, 0x83, 0x83, 0x83, 0x93, 0x93, 0x93, 0xa3, 0xa3, 0xa3, 0xab, 0xab, 0xab, 0xa8, 0xa8, 0xa8, 0x9b, 0x9b, 0x9b, 0x00, 0x00, 0x00,
1106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x72, 0x72, 0x8e, 0x8e, 0x8e, 0xa4, 0xa4, 0xa4, 0xbb, 0xbb, 0xbb, 0xc4, 0xc4, 0xc4, 0xc1, 0xc1, 0xc1, 0xaf, 0xaf, 0xaf, 0x00, 0x00, 0x00,
1107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x90, 0x90, 0x90, 0xa6, 0xa6, 0xa6, 0xbe, 0xbe, 0xbe, 0xc8, 0xc8, 0xc8, 0xc4, 0xc4, 0xc4, 0x8e, 0x8e, 0x8e, 0x00, 0x00, 0x00,
1108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1113 int frameIndex = 0;
1114 int filmHoleIndex = 0;
1115 int offset = (videoFrame->vfr_width * 3) - 3;
1116 UBYTE *pRGB = avInfo->avinf_pFrame->data[0];
1117 ULONG i;
1119 for (i = 0; i < videoFrame->vfr_height; ++i)
1121 ULONG j;
1123 for (j = 0; j < FILMHOLE_WIDTH * 3; j+=3)
1125 int currentFilmHoleIndex = filmHoleIndex + j;
1127 pRGB[frameIndex + j] = filmHole[currentFilmHoleIndex];
1128 pRGB[frameIndex + j + 1] = filmHole[currentFilmHoleIndex + 1];
1129 pRGB[frameIndex + j + 2] = filmHole[currentFilmHoleIndex + 2];
1131 pRGB[frameIndex + offset - j] = filmHole[currentFilmHoleIndex];
1132 pRGB[frameIndex + offset - j + 1] = filmHole[currentFilmHoleIndex + 1];
1133 pRGB[frameIndex + offset - j + 2] = filmHole[currentFilmHoleIndex + 2];
1135 frameIndex += videoFrame->vfr_lineSize;
1136 filmHoleIndex = (i % FILMHOLE_HEIGHT) * FILMHOLE_WIDTH * 3;
1140 //-----------------------------------------------------------------------------
1142 #define BORING_IMAGE_VARIANCE 512.0 /* Tweak this if necessary */
1144 /* This function attempts to detect images that are mostly solid images
1145 * It does this by calculating the statistical variance of the
1146 * black-and-white image */
1147 static BOOL IsInterestingFrame(const struct AVInfo *avInfo)
1149 /* We're gonna assume 8-bit samples. If anyone uses anything different,
1150 * it doesn't really matter cause it's gonna be ugly anyways */
1151 float variance = 0.0f;
1152 float average = 0.0f;
1153 ULONG NumberOfSamples;
1154 ULONG y;
1156 /* FIXME: If this proves to be a performance issue, this function
1157 * can be modified to perhaps only check 3 rows. I doubt this'll
1158 * be a problem though. */
1160 NumberOfSamples = avInfo->avinf_pCodecContext->width * avInfo->avinf_pCodecContext->height;
1161 NumberOfSamples /= 2;
1163 // Iterate through the RGB image to calculate average
1164 for (y = 0; y < avInfo->avinf_pCodecContext->height; y += 2)
1166 const UBYTE *pBuffer = avInfo->avinf_pRGBFrame->data[0] + y * avInfo->avinf_pRGBFrame->linesize[0];
1167 ULONG x;
1169 for (x = 0; x < avInfo->avinf_pCodecContext->width; x++)
1171 average += (float) (pBuffer[0] + pBuffer[1] + pBuffer[2]);
1172 pBuffer += 3;
1175 average /= ((float) (3 * NumberOfSamples));
1177 /* Calculate the variance */
1178 for (y = 0; y < avInfo->avinf_pCodecContext->height; y++)
1180 const UBYTE *pBuffer = avInfo->avinf_pRGBFrame->data[0] + y * avInfo->avinf_pRGBFrame->linesize[0];
1181 ULONG x;
1183 for (x = 0; x < avInfo->avinf_pCodecContext->width; x++)
1185 float tmp = (float) ((pBuffer[0] + pBuffer[1] + pBuffer[2]) / 3) - average;
1187 variance += tmp * tmp;
1188 pBuffer += 3;
1191 variance /= ((float) (NumberOfSamples - 1));
1193 d1( { \
1194 char buffer[80]; \
1195 sprintf(buffer, "average=%f variance=%f", average, variance); \
1196 KPrintF("%s/%s/%ld: %s\n", __FILE__, __FUNC__, __LINE__, buffer); \
1197 } );
1199 d1(KPrintF("%s/%s/%ld: IsInterestingFrame=%ld\n", __FILE__, __FUNC__, __LINE__, (variance > BORING_IMAGE_VARIANCE)));
1201 return (variance > BORING_IMAGE_VARIANCE);
1204 //-----------------------------------------------------------------------------
1206 static BOOL FindInterestingFrame(struct AVInfo *avInfo)
1208 ULONG n = 0;
1209 float framePosition = 1.2;
1210 float FramePositionStep = 0.25;
1212 for (n = 0; !IsInterestingFrame(avInfo) && n < 10; n++)
1214 d1(KPrintF("%s/%s/%ld: n=%ld\n", __FILE__, __FUNC__, __LINE__, n));
1215 if (!VideoSeekFrame(avInfo, framePosition))
1217 d1(KPrintF("%s/%s/%ld: VideoSeekFrame failed n=%ld\n", __FILE__, __FUNC__, __LINE__, n));
1218 return FALSE;
1220 framePosition += FramePositionStep;
1221 FramePositionStep += FramePositionStep; // double step size on each loop
1224 d1(KPrintF("%s/%s/%ld: Success n=%ld\n", __FILE__, __FUNC__, __LINE__, n));
1226 return TRUE;
1229 //-----------------------------------------------------------------------------
1231 static void av_log_dummy_callback(void* ptr, int level, const char* fmt, va_list vl)
1233 #if 0
1234 char buf[256];
1236 d1(KPrintF("%s/%s/%ld: fmt=<%s> level=%ld\n", __FILE__, __FUNC__, __LINE__, fmt, level));
1238 (void) ptr;
1239 (void) fmt;
1240 (void) vl;
1242 vsnprintf(buf, sizeof(buf), fmt, vl);
1243 d1(KPrintF("%s/%s/%ld: %s\n", __FILE__, __FUNC__, __LINE__, buf));
1244 #endif
1247 //-----------------------------------------------------------------------------
1249 void abort(void)
1251 while (1)
1255 //-----------------------------------------------------------------------------
1257 #if BYTEDUMP
1258 static void ByteDump(const unsigned char *Data, size_t Length)
1260 unsigned long count;
1261 unsigned char Line[80], *lp;
1263 lp = Line;
1264 for (count=0; count<Length; count++)
1266 *lp++ = isprint(*Data) ? *Data : '.';
1267 KPrintF("%02lx ", (ULONG) *Data++);
1268 if ((count+1) % 16 == 0)
1270 *lp = '\0';
1271 lp = Line;
1272 KPrintF("\t%s\n", Line);
1276 *lp = '\0';
1277 while (count % 16 != 0)
1279 KPrintF(" ");
1280 count++;
1282 KPrintF("\t%s\n", Line);
1284 #endif /* BYTEDUMP */
1286 //-----------------------------------------------------------------------------