[xiph-commits] r6907 - in trunk/theora-tools: . theoraplay
giles at dactyl.lonelymoon.com
giles
Mon Jun 28 02:40:37 PDT 2004
Author: giles
Date: Mon Jun 28 02:40:37 2004
New Revision: 6907
Added:
trunk/theora-tools/theoraplay/
trunk/theora-tools/theoraplay/theoraplay.c
Log:
Initial checkin of work in progress. This doesn't work yet.
SDL-based 'theoraplay' application using liboggz for mux.
Currently plays back theora video, decodes but does not
play back audio.
Added: trunk/theora-tools/theoraplay/theoraplay.c
===================================================================
--- trunk/theora-tools/theoraplay/theoraplay.c 2004-06-28 07:57:15 UTC (rev 6906)
+++ trunk/theora-tools/theoraplay/theoraplay.c 2004-06-28 09:40:33 UTC (rev 6907)
@@ -0,0 +1,265 @@
+/********************************************************************
+ * *
+ * COPYRIGHT (C) 2004 Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ * Distributed under the terms of the GNU GPL *
+ * *
+ ********************************************************************/
+
+/* this is a liboggz based player for the Xiph.org codecs
+ encapsulated in Ogg bitstreams. It might want to eventually
+ replace ogg123.
+
+ quick-and-dirty for now. compile with:
+
+ gcc -o theoraplay theoraplay.c \
+ `sdl-config --cflags` `pkg-config --cflags theora vorbis oggz ogg` \
+ `sdl-config --libs` `pkg-config --libs theora vorbis oggz ogg`
+
+ relies only on SDL for a/v playback.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <oggz/oggz.h>
+#include <theora/theora.h>
+#include <vorbis/codec.h>
+
+#include <SDL.h>
+
+static int read_packet_null(OGGZ *oggz, ogg_packet *op, long serialno,
+ void *user_data)
+{
+ /* report end of stream */
+ if (op->e_o_s) {
+ fprintf(stderr, "0x%08x end of stream\n");
+ }
+ /* otherwise do nothing */
+ return 0;
+}
+
+typedef struct {
+ int decoding, flag;
+ theora_info ti;
+ theora_comment tc;
+ theora_state td;
+ SDL_Surface *screen;
+ SDL_Overlay *yuv_overlay;
+ SDL_Rect rect;
+} theora_playback;
+
+static int video_open(theora_playback *this)
+{
+ theora_info *ti = &(this->ti);
+
+ fprintf(stderr, "Opening %dx%d video window\n",
+ ti->frame_width, ti->frame_height);
+
+ this->screen =
+ SDL_SetVideoMode(ti->frame_width, ti->frame_height,
+ 0, SDL_SWSURFACE);
+ if (this->screen == NULL ) {
+ fprintf(stderr, "Unable to set %dx%d video: %s\n",
+ ti->frame_width,ti->frame_height,
+ SDL_GetError());
+ return 1;
+ }
+
+ this->yuv_overlay =
+ SDL_CreateYUVOverlay(ti->frame_width, ti->frame_height,
+ SDL_YV12_OVERLAY,
+ this->screen);
+ if (this->yuv_overlay == NULL) {
+ fprintf(stderr, "SDL: Couldn't create SDL_yuv_overlay: %s\n",
+ SDL_GetError());
+ return 2;
+ }
+
+ this->rect.x = 0;
+ this->rect.y = 0;
+ this->rect.w = ti->frame_width;
+ this->rect.h = ti->frame_height;
+
+ SDL_DisplayYUVOverlay(this->yuv_overlay, &(this->rect));
+
+
+}
+
+static void video_write(theora_playback *this)
+{
+ SDL_Overlay *overlay = this->yuv_overlay;
+ theora_info *ti = &(this->ti);
+ yuv_buffer yuv;
+ int crop_offset;
+ int i;
+ theora_decode_YUVout(&(this->td),&yuv);
+#if DEBUG
+ fprintf(stderr, "playing video frame at %ld\n",
+ this->td.granulepos);
+#endif
+ if (SDL_LockYUVOverlay(overlay) < 0) return;
+
+ crop_offset=ti->offset_x+yuv.y_stride*ti->offset_y;
+ for(i=0;i<overlay->h;i++)
+ memcpy(overlay->pixels[0]+overlay->pitches[0]*i,
+ yuv.y+crop_offset+yuv.y_stride*i,
+ overlay->w);
+ crop_offset=(ti->offset_x/2)+(yuv.uv_stride)*(ti->offset_y/2);
+ for(i=0;i<overlay->h/2;i++){
+ memcpy(overlay->pixels[1]+overlay->pitches[1]*i,
+ yuv.v+crop_offset+yuv.uv_stride*i,
+ overlay->w/2);
+ memcpy(overlay->pixels[2]+overlay->pitches[2]*i,
+ yuv.u+crop_offset+yuv.uv_stride*i,
+ overlay->w/2);
+ }
+
+ SDL_UnlockYUVOverlay(this->yuv_overlay);
+
+ SDL_DisplayYUVOverlay(this->yuv_overlay, &(this->rect));
+}
+
+static int read_packet_theora(OGGZ *oggz, ogg_packet *op, long serialno,
+ void *user_data)
+{
+ theora_playback *this = (theora_playback*)user_data;
+ theora_state *td = &(this->td);
+ int result = 0;
+
+ /* are we still looking for header packets? */
+ if (this->flag < 3) {
+ result = theora_decode_header(&(this->ti),&(this->tc),op);
+ if (result < 0) {
+ fprintf(stderr, "0x%08x error parsing theora header!\n", serialno);
+ return result;
+ }
+ this->flag++;
+ if (this->flag == 1) {
+ fprintf(stderr, "0x%08x Theora Video: %dx%d frames at %.3fHz\n",
+ serialno,
+ this->ti.frame_width, this->ti.frame_height,
+ (float)this->ti.fps_numerator/(float)this->ti.fps_denominator);
+
+ }
+ } else {
+ if (this->flag < 4) {
+ theora_decode_init(td,&(this->ti));
+ video_open(this);
+ this->flag++;
+#ifdef DEBUG
+ fprintf(stderr, "0x%08x encoded by: %s\n",
+ serialno, this->tc.vendor);
+#endif
+ }
+ theora_decode_packetin(td,op);
+ video_write(this);
+ }
+ return 0;
+}
+
+typedef struct {
+ int decoding, flag;
+ vorbis_info vi;
+ vorbis_comment vc;
+ vorbis_dsp_state vd;
+ vorbis_block vb;
+} vorbis_playback;
+
+static int read_packet_vorbis(OGGZ *oggz, ogg_packet *op, long serialno,
+ void *user_data)
+{
+ vorbis_playback *this = (vorbis_playback*)user_data;
+ int result = 0;
+
+ /* are we still looking for header packets? */
+ if (this->flag < 3) {
+ result = vorbis_synthesis_headerin(&(this->vi),&(this->vc),op);
+ if (result < 0) {
+ fprintf(stderr, "0x%08x error parsing vorbis header!\n", serialno);
+ return result;
+ }
+ this->flag++;
+ if (this->flag == 1) {
+ fprintf(stderr, "0x%08x Vorbis Audio: %d channels at %dHz\n",
+ serialno, this->vi.channels, this->vi.rate);
+ }
+ } else {
+ if (this->flag < 4) {
+ vorbis_synthesis_init(&(this->vd),&(this->vi));
+ vorbis_block_init(&(this->vd),&(this->vb));
+ // audio_open(this);
+ this->flag++;
+#if DEBUG
+ fprintf(stderr, "0x%08x encoded by: %s\n",
+ serialno, this->vc.vendor);
+#endif
+ }
+ if (vorbis_synthesis(&(this->vb),op) == 0)
+ vorbis_synthesis_blockin(&(this->vd),&(this->vb));
+ // audio_write(this);
+ }
+ return 0;
+}
+
+
+static int read_packet_dispatch(OGGZ *oggz, ogg_packet *op, long serialno,
+ void *user_data)
+{
+ const unsigned char theora_magic[] = "\x80theora";
+ const unsigned char vorbis_magic[] = "\x01vorbis";
+
+ /* we're called for new streams; try and identify the type */
+ if (!memcmp(op->packet, theora_magic, 7)) {
+ theora_playback *pb = malloc(sizeof(*pb));
+ pb->flag = 0; pb->decoding = 1;
+ theora_info_init(&(pb->ti));
+ theora_comment_init(&(pb->tc));
+ if (!read_packet_theora(oggz, op, serialno, pb))
+ oggz_set_read_callback(oggz, serialno, read_packet_theora, pb);
+ } else if (!memcmp(op->packet, vorbis_magic, 7)) {
+ vorbis_playback *pb = malloc(sizeof(*pb));
+ pb->flag = 0; pb->decoding = 1;
+ vorbis_info_init(&(pb->vi));
+ vorbis_comment_init(&(pb->vc));
+ if (!read_packet_vorbis(oggz, op, serialno, pb))
+ oggz_set_read_callback(oggz, serialno, read_packet_vorbis, pb);
+ } else {
+ fprintf(stderr, "0x%08x unrecognized codec!\n", serialno);
+ oggz_set_read_callback(oggz, serialno, read_packet_null, NULL);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ OGGZ *oggz;
+
+ if (argc < 2) {
+ printf("usage: %s <file.ogg>\n", argv[0]);
+ }
+
+ oggz = oggz_open((char*)argv[1], OGGZ_READ | OGGZ_AUTO);
+ if (oggz == NULL) {
+ fprintf(stderr, "unable to open '%s'\n", argv[1]);
+ exit(1);
+ }
+
+ /* install our dispatcher for new streams */
+ oggz_set_read_callback(oggz, -1, read_packet_dispatch, NULL);
+
+ if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0) {
+ fprintf(stderr, "Unable to initialize playback: %s\n",
+ SDL_GetError());
+ return 1;
+ }
+
+ while (oggz_read(oggz, 4096) > 0);
+
+ oggz_close(oggz);
+
+ SDL_Quit();
+
+ return 0;
+}
More information about the commits
mailing list