Hello, I'm new to this list, and pretty much also to the codec universe. In a computer game I'm working on, there is an 3D TV-screen onto which I project the frames of a movie. The movie is of course stored as theora, no audio as it's not needed yet. I have it working so far, extracting a frame and uploading it to the graphics card when the scene is drawn. The example file dump_video.c gave me most of what I needed. ...But I can't seem to handle end-of-stream very well. I would like to be able to rewind. First I tried the brute force method: if (videoStream.eof()) { ogg_stream_clear (&theoraStreamState); theora_clear (&theoraState); theora_comment_clear (&theoraComment); theora_info_clear (&theoraInfo); ogg_sync_clear (&oggSyncState); videoStream.clear(); videoStream.close(); init_the_movie_like_it_was_inited_the_first_time(); } But I got a crash when trying to re-initialize: theora_decode_init (&theoraState, &theoraInfo); Specifically this line in quant.c gave me a problem: qmat = ci->range_table[0]->qmat; According to my debugger (Visual Studio 7.1) ci->range_table[0] = 0x00000000. No doubt the problem is related to some sort of clearing that I still need to do. Alternatively, I want to seek to the proper position in the file and.... eh... just continue reading? Truth is I don't really know what I'm doing here.... Here's the complete decoder-file (VideoStreamTheora.h and VideoStreamTheora.cpp) for reference. If you answer, perhaps you should cut it away from the reply :-) Many thanks for the free codecs. ------------- HEADER FILE ------------- #ifndef VIDEOSTREAMTHEORA_H_ #define VIDEOSTREAMTHEORA_H_ #include <fstream> #include <ogg/ogg.h> #include <theora/theora.h> #include "VideoStreamable.h" namespace camilla { class VideoStreamTheora : public VideoStreamable { int movieLengthBytes; int moviePositionBytes; ogg_sync_state oggSyncState; ogg_page oggPage; ogg_packet oggPacket; ogg_stream_state vorbisStreamState; ogg_stream_state theoraStreamState; theora_info theoraInfo; theora_comment theoraComment; theora_state theoraState; int theoraPageCount; yuv_buffer yuvBuffer; std::ifstream videoStream; void rewind (); void initMovie (); void exitMovie (); int buffer_data (); int queue_page (ogg_page *oggPage); void decode_frame (); public: VideoStreamTheora(); virtual ~VideoStreamTheora(); virtual void decodeAndRenderFrameToTexture (irr::video::ITexture* texture); }; } #endif /*VIDEOSTREAMTHEORA_H_*/ -------------SOURCE FILE ------------- #include <iostream> #include "VideoStreamTheora.h" namespace camilla { VideoStreamable::~VideoStreamable() { } VideoStreamTheora::VideoStreamTheora() { theoraPageCount = 0; initMovie(); } void VideoStreamTheora::rewind () { videoStream.clear(); videoStream.close(); videoStream.open ("test.ogg", std::ios::binary); videoStream.seekg (0, std::ios::beg); } void VideoStreamTheora::exitMovie () { ogg_stream_clear (&theoraStreamState); theora_clear (&theoraState); theora_comment_clear (&theoraComment); theora_info_clear (&theoraInfo); ogg_sync_clear (&oggSyncState); videoStream.clear(); videoStream.close(); } void VideoStreamTheora::initMovie () { videoStream.open ("shit.ogg", std::ios::binary); if (! videoStream.good()) throw "Error: VideoStreamTheora::initMovie: bad file."; videoStream.seekg (0, std::ios::end); movieLengthBytes = videoStream.tellg(); videoStream.seekg (0, std::ios::beg); ogg_sync_init (&oggSyncState); theora_comment_init (&theoraComment); theora_info_init (&theoraInfo); // Fetch from the ogg-stream until we have the INITIAL PAGES of the theora stream for (bool doneScanningHeaders=false; ! doneScanningHeaders; ) { if (buffer_data ()==0) throw "Error: VideoStreamTheora::initMovie: Couldn't get initial packets."; while (ogg_sync_pageout (&oggSyncState, &oggPage)>0) { ogg_stream_state testStreamState; if (! ogg_page_bos (&oggPage)) { queue_page (&oggPage); doneScanningHeaders = true; break; } ogg_stream_init (&testStreamState, ogg_page_serialno (&oggPage)); ogg_stream_pagein (&testStreamState, &oggPage); ogg_stream_packetout (&testStreamState, &oggPacket); if(theoraPageCount==0 && theora_decode_header (&theoraInfo,&theoraComment, &oggPacket) >= 0) { memcpy (&theoraStreamState, &testStreamState,sizeof(testStreamState)); theoraPageCount = 1; } else { ogg_stream_clear (&testStreamState); } } } while (theoraPageCount && (theoraPageCount < 3)) { int ret; while (theoraPageCount && (theoraPageCount < 3) && (ret=ogg_stream_packetout (&theoraStreamState, &oggPacket))) { if (ret<0) throw "Error parsing Theora stream headers; corrupt stream?"; if (theora_decode_header (&theoraInfo, &theoraComment, &oggPacket)) throw "Error parsing Theora stream headers; corrupt stream?"; ++ theoraPageCount; if (theoraPageCount==3) break; } if (ogg_sync_pageout (&oggSyncState, &oggPage) > 0) queue_page (&oggPage); else { if (buffer_data () == 0) throw "End of file while searching for codec headers."; } } if (theoraPageCount > 0) { theora_decode_init (&theoraState, &theoraInfo); std::cout << "Ogg logical stream " << theoraStreamState.serialno << " is Theora " << theoraInfo.width << "x" << theoraInfo.height << " " << ((double)theoraInfo.fps_numerator/theoraInfo.fps_denominator) << " fps video " << " Encoded frame content is size: " <<theoraInfo.frame_width << "x" << theoraInfo.frame_height << " offset: " << theoraInfo.offset_x << "," << theoraInfo.offset_y << " Colorspace: " << theoraInfo.colorspace << std::endl; } else { theora_info_clear (&theoraInfo); theora_comment_clear (&theoraComment); throw "Bad theora file. Quitting now."; } while (ogg_sync_pageout(&oggSyncState, &oggPage)>0) { queue_page (&oggPage); } decode_frame(); } VideoStreamTheora::~VideoStreamTheora() { } void VideoStreamTheora::decode_frame () { ogg_int64_t videobuf_granulepos = -1; double videobuf_time = 0; for (bool videobuf_ready = false; ! videobuf_ready; ) { if (ogg_stream_packetout (&theoraStreamState, &oggPacket) > 0) { theora_decode_packetin (&theoraState, &oggPacket); videobuf_granulepos = theoraState.granulepos; videobuf_time = theora_granule_time (&theoraState, videobuf_granulepos); videobuf_ready = true; } if (! videobuf_ready && videoStream.eof()) { //throw "Can't decode the frame! EOF reached"; return; } if (! videobuf_ready) { buffer_data (); while (ogg_sync_pageout (&oggSyncState, &oggPage) > 0) { queue_page (&oggPage); } } } theora_decode_YUVout (&theoraState, &yuvBuffer); } int VideoStreamTheora::buffer_data () { char *buffer = ogg_sync_buffer (&oggSyncState,4096); int bytes = videoStream.tellg(); videoStream.read (buffer, 4096); bytes = int(videoStream.tellg()) - bytes; ogg_sync_wrote (&oggSyncState, bytes); return(bytes); } int VideoStreamTheora::queue_page (ogg_page *oggPage) { if(theoraPageCount > 0) ogg_stream_pagein (&theoraStreamState, oggPage); return 0; } void VideoStreamTheora::decodeAndRenderFrameToTexture (irr::video::ITexture* texture) { using namespace irr; using namespace irr::core; moviePositionBytes = videoStream.tellg(); // DIDN'T WORK: //if (ogg_page_eos (&oggPage)) // DIDN'T WORK: //if (moviePositionBytes == movieLengthBytes) // EOF BEING DETECTED, BUT THE REWIND / EXIT+INIT DOESN'T: if (videoStream.eof()) { rewind(); //exitMovie(); //initMovie(); } decode_frame(); dimension2d<s32> texDim = texture->getSize(); long* texMem = (long*) texture->lock(); for (int y=0; y<texDim.Height; ++y) { for (int x=0; x<texDim.Width; ++x) { int Y = yuvBuffer.y [y*yuvBuffer.y_stride + x]; int U = yuvBuffer.u [(y/2)*yuvBuffer.uv_stride + (x/2)]; int V = yuvBuffer.v [(y/2)*yuvBuffer.uv_stride + (x/2)]; int B = (int)(1.164*(Y - 16) + 2.018*(U - 128)); int G = (int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128)); int R = (int)(1.164*(Y - 16) + 1.596*(V - 128)); *texMem++ = ((R&0xFF)<<16) | ((G&0xFF)<<8) | ((B&0xFF)); } } texture->unlock(); } }