Skip to content

Commit

Permalink
Add support for multiple pixel layouts, plus RGB/RGBA conversion supp…
Browse files Browse the repository at this point in the history
…ort.
  • Loading branch information
icculus committed Jun 15, 2011
1 parent 573d67d commit 830c4a9
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 75 deletions.
134 changes: 112 additions & 22 deletions test/sdltheoraplay.c
Expand Up @@ -9,6 +9,8 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include "theoraplay.h"
#include "SDL.h"

Expand Down Expand Up @@ -88,21 +90,70 @@ static void queue_audio(const THEORAPLAY_PcmAudioItem *audio)
} // queue_audio


static void playfile(const char *fname)
static int need_overlay(const THEORAPLAY_VideoFormat vidfmt)
{
return (vidfmt == THEORAPLAY_VIDFMT_YV12);
} // need_overlay


static void setcaption(const char *fname,
const THEORAPLAY_VideoFormat vidfmt,
const THEORAPLAY_YuvVideoItem *video,
const THEORAPLAY_PcmAudioItem *audio)
{
char buf[1024];
const char *fmtstr = "???";
const char *basefname = NULL;

if (!video)
return; // no caption to set.

basefname = strrchr(fname, '/');
if (!basefname)
basefname = fname;
else
basefname++;

switch (vidfmt)
{
case THEORAPLAY_VIDFMT_RGB: fmtstr = "RGB"; break;
case THEORAPLAY_VIDFMT_RGBA: fmtstr = "RGBA"; break;
case THEORAPLAY_VIDFMT_YV12: fmtstr = "YV12"; break;
default: assert(0 && "Unexpected video format!"); break;
} // switch

if (audio)
{
snprintf(buf, sizeof (buf), "%s (%ux%u, %.2gfps, %s, %uch, %uHz)",
basefname, video->width, video->height, video->fps,
fmtstr, audio->channels, audio->freq);
} // if
else
{
snprintf(buf, sizeof (buf), "%s (%ux%u, %ffps, %s, no audio)",
basefname, video->width, video->height, video->fps,
fmtstr);
} // else

SDL_WM_SetCaption(buf, basefname);
} // setcaption


static void playfile(const char *fname, const THEORAPLAY_VideoFormat vidfmt)
{
THEORAPLAY_Decoder *decoder = NULL;
const THEORAPLAY_YuvVideoItem *video = NULL;
const THEORAPLAY_PcmAudioItem *audio = NULL;
const char *basefname = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *shadow = NULL;
SDL_Overlay *overlay = NULL;
SDL_Event event;
Uint32 framems = 0;
int initfailed = 0;
int quit = 0;

printf("Trying file '%s' ...\n", fname);
decoder = THEORAPLAY_startDecode(fname, 20);
decoder = THEORAPLAY_startDecode(fname, 20, vidfmt);
if (!decoder)
{
fprintf(stderr, "Failed to start decoding '%s'!\n", fname);
Expand All @@ -115,13 +166,6 @@ static void playfile(const char *fname)
return;
} // if

basefname = strrchr(fname, '/');
if (!basefname)
basefname = fname;
else
basefname++;
SDL_WM_SetCaption(basefname, basefname);

// wait until we have a video and audio packet, so we can set up hardware.
// !!! FIXME: we need an API to decide if this file has only audio/video.
while (!video || !audio)
Expand All @@ -134,7 +178,9 @@ static void playfile(const char *fname)
// Set the video mode as soon as we know what it should be.
if (video)
{
const int needoverlay = need_overlay(vidfmt);
framems = (video->fps == 0.0) ? 0 : ((Uint32) (1000.0 / video->fps));
setcaption(fname, vidfmt, video, audio);
screen = SDL_SetVideoMode(video->width, video->height, 0, 0);
if (!screen)
fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError());
Expand All @@ -144,14 +190,34 @@ static void playfile(const char *fname)
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_Flip(screen);

overlay = SDL_CreateYUVOverlay(video->width, video->height,
SDL_YV12_OVERLAY, screen);
if (needoverlay)
{
overlay = SDL_CreateYUVOverlay(video->width, video->height,
SDL_YV12_OVERLAY, screen);

if (!overlay)
fprintf(stderr, "YUV Overlay failed: %s\n", SDL_GetError());
if (!overlay)
fprintf(stderr, "YUV Overlay failed: %s\n", SDL_GetError());
} // if
else
{
const int alpha = (vidfmt == THEORAPLAY_VIDFMT_RGBA);
const int bits = 24 + (alpha * 8);
const Uint32 rmask = SDL_SwapLE32(0xFF0000FF);
const Uint32 gmask = SDL_SwapLE32(0x0000FF00);
const Uint32 bmask = SDL_SwapLE32(0x00FF0000);
const Uint32 amask = 0x00000000;
shadow = SDL_CreateRGBSurface(SDL_SWSURFACE,
video->width, video->height,
bits, rmask, gmask, bmask, amask);
if (!shadow)
fprintf(stderr, "Shadow surface failed: %s\n", SDL_GetError());

assert(!shadow || !SDL_MUSTLOCK(shadow));
assert(!shadow || (shadow->pitch == (video->width * (bits/8))));
} // else
} // else

initfailed = quit = (!screen || !overlay);
initfailed = quit = (!screen || (needoverlay ? !overlay : !shadow));
} // if

// Open the audio device as soon as we know what it should be.
Expand Down Expand Up @@ -212,6 +278,16 @@ static void playfile(const char *fname)
} // if
} // if

else if (!overlay) // not a YUV thing.
{
memcpy(shadow->pixels, video->pixels, shadow->h * shadow->pitch);
// shadow is a software surface, and is thus never "lost".
// Keep trying if the screen surface is lost, though.
while (SDL_BlitSurface(shadow, NULL, screen, NULL) == -2)
SDL_Delay(1000);
SDL_Flip(screen);
} // else if

else if (SDL_LockYUVOverlay(overlay) == -1)
{
static int warned = 0;
Expand All @@ -220,13 +296,14 @@ static void playfile(const char *fname)
warned = 1;
fprintf(stderr, "Couldn't lock YUV overlay: %s\n", SDL_GetError());
} // if
} // if
} // else if

else
{
SDL_Rect dstrect = { 0, 0, video->width, video->height };
const int w = video->width;
const int h = video->height;
const Uint8 *y = (const Uint8 *) video->yuv;
const Uint8 *y = (const Uint8 *) video->pixels;
const Uint8 *u = y + (w * h);
const Uint8 *v = u + ((w/2) * (h/2));
Uint8 *dst;
Expand Down Expand Up @@ -282,15 +359,17 @@ static void playfile(const char *fname)
switch (event.type)
{
case SDL_VIDEOEXPOSE:
{
SDL_Rect dstrect = { 0, 0, screen->w, screen->h };
SDL_DisplayYUVOverlay(overlay, &dstrect);
if (overlay)
{
SDL_Rect dstrect = { 0, 0, screen->w, screen->h };
SDL_DisplayYUVOverlay(overlay, &dstrect);
} // if
break;
} // case

case SDL_QUIT:
quit = 1;
break;

case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE)
quit = 1;
Expand All @@ -315,6 +394,7 @@ static void playfile(const char *fname)
else
printf("done with this file!\n");

if (shadow) SDL_FreeSurface(shadow);
if (overlay) SDL_FreeYUVOverlay(overlay);
if (video) THEORAPLAY_freeVideo(video);
if (audio) THEORAPLAY_freeAudio(audio);
Expand All @@ -325,10 +405,20 @@ static void playfile(const char *fname)

int main(int argc, char **argv)
{
THEORAPLAY_VideoFormat vidfmt = THEORAPLAY_VIDFMT_YV12;
int i;

for (i = 1; i < argc; i++)
playfile(argv[i]);
{
if (strcmp(argv[i], "--rgb") == 0)
vidfmt = THEORAPLAY_VIDFMT_RGB;
else if (strcmp(argv[i], "--rgba") == 0)
vidfmt = THEORAPLAY_VIDFMT_RGBA;
else if (strcmp(argv[i], "--yv12") == 0)
vidfmt = THEORAPLAY_VIDFMT_YV12;
else
playfile(argv[i], vidfmt);
} // for

printf("done all files!\n");

Expand Down
71 changes: 43 additions & 28 deletions test/testtheoraplay.c
Expand Up @@ -8,45 +8,60 @@

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "theoraplay.h"

int main(int argc, char **argv)
static void dofile(const char *fname, const THEORAPLAY_VideoFormat vidfmt)
{
THEORAPLAY_Decoder *decoder = NULL;
const THEORAPLAY_YuvVideoItem *video = NULL;
const THEORAPLAY_PcmAudioItem *audio = NULL;

printf("Trying file '%s' ...\n", fname);
decoder = THEORAPLAY_startDecode(fname, 20, vidfmt);
while (THEORAPLAY_isDecoding(decoder))
{
video = THEORAPLAY_getVideo(decoder);
if (video)
{
printf("Got video frame (%u ms)!\n", video->playms);
THEORAPLAY_freeVideo(video);
} // if

audio = THEORAPLAY_getAudio(decoder);
if (audio)
{
printf("Got %d frames of audio (%u ms)!\n", audio->frames, audio->playms);
THEORAPLAY_freeAudio(audio);
} // if

if (!video && !audio)
usleep(10000);
} // while

if (THEORAPLAY_decodingError(decoder))
printf("There was an error decoding this file!\n");
else
printf("done with this file!\n");

THEORAPLAY_stopDecode(decoder);
} // dofile

int main(int argc, char **argv)
{
THEORAPLAY_VideoFormat vidfmt = THEORAPLAY_VIDFMT_YV12;
int i;

for (i = 1; i < argc; i++)
{
printf("Trying file '%s' ...\n", argv[i]);
decoder = THEORAPLAY_startDecode(argv[i], 20);
while (THEORAPLAY_isDecoding(decoder))
{
video = THEORAPLAY_getVideo(decoder);
if (video)
{
printf("Got video frame (%u ms)!\n", video->playms);
THEORAPLAY_freeVideo(video);
} // if

audio = THEORAPLAY_getAudio(decoder);
if (audio)
{
printf("Got %d frames of audio (%u ms)!\n", audio->frames, audio->playms);
THEORAPLAY_freeAudio(audio);
} // if

if (!video && !audio)
usleep(10000);
} // while

if (THEORAPLAY_decodingError(decoder))
printf("There was an error decoding this file!\n");
if (strcmp(argv[i], "--rgb") == 0)
vidfmt = THEORAPLAY_VIDFMT_RGB;
else if (strcmp(argv[i], "--rgba") == 0)
vidfmt = THEORAPLAY_VIDFMT_RGBA;
else if (strcmp(argv[i], "--yv12") == 0)
vidfmt = THEORAPLAY_VIDFMT_YV12;
else
printf("done with this file!\n");

THEORAPLAY_stopDecode(decoder);
dofile(argv[i], vidfmt);
} // for

printf("done all files!\n");
Expand Down

0 comments on commit 830c4a9

Please sign in to comment.