dump_video.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /********************************************************************
  2. * *
  3. * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
  4. * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
  5. * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  6. * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
  7. * *
  8. * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2004 *
  9. * by the Xiph.Org Foundation http://www.xiph.org/ *
  10. * *
  11. ********************************************************************
  12. function: example dumpvid application; dumps Theora streams
  13. last mod: $Id: dump_video.c,v 1.10 2004/03/08 06:44:26 giles Exp $
  14. ********************************************************************/
  15. /* By Mauricio Piacentini (mauricio at xiph.org) */
  16. /* simply dump decoded YUV data, for verification of theora bitstream */
  17. #ifdef HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #define _GNU_SOURCE
  21. #define _LARGEFILE_SOURCE
  22. #define _LARGEFILE64_SOURCE
  23. #define _FILE_OFFSET_BITS 64
  24. #include <stdio.h>
  25. #include <unistd.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #if defined(_WIN32)
  31. #include <io.h>
  32. #endif
  33. #include <fcntl.h>
  34. #include <math.h>
  35. #include <signal.h>
  36. #include "getopt.h"
  37. #include "theora/theora.h"
  38. const char *optstring = "o:r";
  39. struct option options [] = {
  40. {"output",required_argument,NULL,'o'},
  41. {"raw",no_argument, NULL, 'r'}, /* Disable YUV4MPEG2 headers if set */
  42. {NULL,0,NULL,0}
  43. };
  44. /* Helper; just grab some more compressed bitstream and sync it for
  45. page extraction */
  46. int buffer_data(FILE *in,ogg_sync_state *oy){
  47. char *buffer=ogg_sync_buffer(oy,4096);
  48. int bytes=fread(buffer,1,4096,in);
  49. ogg_sync_wrote(oy,bytes);
  50. return(bytes);
  51. }
  52. /* never forget that globals are a one-way ticket to Hell */
  53. /* Ogg and codec state for demux/decode */
  54. ogg_sync_state oy;
  55. ogg_page og;
  56. ogg_stream_state vo;
  57. ogg_stream_state to;
  58. theora_info ti;
  59. theora_comment tc;
  60. theora_state td;
  61. int theora_p=0;
  62. int stateflag=0;
  63. /* single frame video buffering */
  64. int videobuf_ready=0;
  65. ogg_int64_t videobuf_granulepos=-1;
  66. double videobuf_time=0;
  67. int raw = 0;
  68. FILE* outfile = NULL;
  69. int got_sigint=0;
  70. static void sigint_handler (int signal) {
  71. got_sigint = 1;
  72. }
  73. /* this is a nop in the current implementation. we could
  74. open a file here or something if so moved. */
  75. static void open_video(void){
  76. return;
  77. }
  78. /* write out the planar YUV frame, uncropped */
  79. static void video_write(void){
  80. int i;
  81. yuv_buffer yuv;
  82. theora_decode_YUVout(&td,&yuv);
  83. if(!raw)
  84. fprintf(outfile, "FRAME\n");
  85. for(i=0;i<yuv.y_height;i++)
  86. fwrite(yuv.y+yuv.y_stride*i, 1, yuv.y_width, outfile);
  87. for(i=0;i<yuv.uv_height;i++)
  88. fwrite(yuv.u+yuv.uv_stride*i, 1, yuv.uv_width, outfile);
  89. for(i=0;i<yuv.uv_height;i++)
  90. fwrite(yuv.v+yuv.uv_stride*i, 1, yuv.uv_width, outfile);
  91. }
  92. /* dump the theora comment header */
  93. static int dump_comments(theora_comment *tc){
  94. int i, len;
  95. char *value;
  96. FILE *out=stdout;
  97. fprintf(out,"Encoded by %s\n",tc->vendor);
  98. if(tc->comments){
  99. fprintf(out, "theora comment header:\n");
  100. for(i=0;i<tc->comments;i++){
  101. if(tc->user_comments[i]){
  102. len=tc->comment_lengths[i];
  103. value=malloc(len+1);
  104. memcpy(value,tc->user_comments[i],len);
  105. value[len]='\0';
  106. fprintf(out, "\t%s\n", value);
  107. free(value);
  108. }
  109. }
  110. }
  111. return(0);
  112. }
  113. /* helper: push a page into the steam for packetization */
  114. static int queue_page(ogg_page *page){
  115. if(theora_p)ogg_stream_pagein(&to,&og);
  116. return 0;
  117. }
  118. static void usage(void){
  119. fprintf(stderr,
  120. "Usage: dumpvid <file.ogg> > outfile\n"
  121. "input is read from stdin if no file is passed on the command line\n"
  122. "\n"
  123. );
  124. }
  125. int main(int argc,char *argv[]){
  126. ogg_packet op;
  127. int long_option_index;
  128. int c;
  129. FILE *infile = stdin;
  130. outfile = stdout;
  131. #ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */
  132. /* Beware the evil ifdef. We avoid these where we can, but this one we
  133. cannot. Don't add any more, you'll probably go to hell if you do. */
  134. _setmode( _fileno( stdin ), _O_BINARY );
  135. _setmode( _fileno( stdout ), _O_BINARY );
  136. #endif
  137. /* Process option arguments. */
  138. while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
  139. switch(c){
  140. case 'o':
  141. outfile=fopen(optarg,"wb");
  142. if(outfile==NULL){
  143. fprintf(stderr,"Unable to open output file '%s'\n", optarg);
  144. exit(1);
  145. }
  146. break;
  147. case 'r':
  148. raw = 1;
  149. break;
  150. default:
  151. usage();
  152. }
  153. }
  154. if(optind<argc){
  155. infile=fopen(argv[optind],"rb");
  156. if(infile==NULL){
  157. fprintf(stderr,"Unable to open '%s' for extraction.\n", argv[optind]);
  158. exit(1);
  159. }
  160. if(++optind<argc){
  161. usage();
  162. exit(1);
  163. }
  164. }
  165. /*
  166. Ok, Ogg parsing. The idea here is we have a bitstream
  167. that is made up of Ogg pages. The libogg sync layer will
  168. find them for us. There may be pages from several logical
  169. streams interleaved; we find the first theora stream and
  170. ignore any others.
  171. Then we pass the pages for our stream to the libogg stream
  172. layer which assembles our original set of packets out of
  173. them. It's the packets that libtheora actually knows how
  174. to handle.
  175. */
  176. /* start up Ogg stream synchronization layer */
  177. ogg_sync_init(&oy);
  178. /* init supporting Theora structures needed in header parsing */
  179. theora_comment_init(&tc);
  180. theora_info_init(&ti);
  181. /* Ogg file open; parse the headers */
  182. /* Vorbis and Theora both depend on some initial header packets
  183. for decoder setup and initialization. We retrieve these first
  184. before entering the main decode loop. */
  185. /* Only interested in Theora streams */
  186. while(!stateflag){
  187. int ret=buffer_data(infile,&oy);
  188. if(ret==0)break;
  189. while(ogg_sync_pageout(&oy,&og)>0){
  190. ogg_stream_state test;
  191. /* is this a mandated initial header? If not, stop parsing */
  192. if(!ogg_page_bos(&og)){
  193. /* don't leak the page; get it into the appropriate stream */
  194. queue_page(&og);
  195. stateflag=1;
  196. break;
  197. }
  198. ogg_stream_init(&test,ogg_page_serialno(&og));
  199. ogg_stream_pagein(&test,&og);
  200. ogg_stream_packetout(&test,&op);
  201. /* identify the codec: try theora */
  202. if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){
  203. /* it is theora -- save this stream state */
  204. memcpy(&to,&test,sizeof(test));
  205. theora_p=1;
  206. }else{
  207. /* whatever it is, we don't care about it */
  208. ogg_stream_clear(&test);
  209. }
  210. }
  211. /* fall through to non-initial page parsing */
  212. }
  213. /* we're expecting more header packets. */
  214. while(theora_p && theora_p<3){
  215. int ret;
  216. /* look for further theora headers */
  217. while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
  218. if(ret<0){
  219. fprintf(stderr,"Error parsing Theora stream headers; corrupt stream?\n");
  220. exit(1);
  221. }
  222. if(theora_decode_header(&ti,&tc,&op)){
  223. printf("Error parsing Theora stream headers; corrupt stream?\n");
  224. exit(1);
  225. }
  226. theora_p++;
  227. if(theora_p==3)break;
  228. }
  229. /* The header pages/packets will arrive before anything else we
  230. care about, or the stream is not obeying spec */
  231. if(ogg_sync_pageout(&oy,&og)>0){
  232. queue_page(&og); /* demux into the stream state */
  233. }else{
  234. int ret=buffer_data(infile,&oy); /* need more data */
  235. if(ret==0){
  236. fprintf(stderr,"End of file while searching for codec headers.\n");
  237. exit(1);
  238. }
  239. }
  240. }
  241. /* Now we have all the required headers. initialize the decoder. */
  242. if(theora_p){
  243. theora_decode_init(&td,&ti);
  244. fprintf(stderr,"Ogg logical stream %x is Theora %dx%d %.02f fps video\nEncoded frame content is %dx%d with %dx%d offset\n",
  245. (unsigned int)to.serialno,ti.width,ti.height,
  246. (double)ti.fps_numerator/ti.fps_denominator,
  247. ti.frame_width, ti.frame_height, ti.offset_x, ti.offset_y);
  248. }else{
  249. /* tear down the partial theora setup */
  250. theora_info_clear(&ti);
  251. theora_comment_clear(&tc);
  252. }
  253. /* open video */
  254. if(theora_p)open_video();
  255. if(!raw)
  256. fprintf(outfile, "YUV4MPEG2 W%d H%d F%d:%d I%c A%d:%d\n",
  257. ti.width, ti.height, ti.fps_numerator, ti.fps_denominator, 'p',
  258. ti.aspect_numerator, ti.aspect_denominator);
  259. /* install signal handler */
  260. signal (SIGINT, sigint_handler);
  261. /* Finally the main decode loop.
  262. It's one Theora packet per frame, so this is pretty
  263. straightforward if we're not trying to maintain sync
  264. with other multiplexed streams.
  265. the videobuf_ready flag is used to maintain the input
  266. buffer in the libogg stream state. If there's no output
  267. frame available at the end of the decode step, we must
  268. need more input data. We could simplify this by just
  269. using the return code on ogg_page_packetout(), but the
  270. flag system extends easily to the case were you care
  271. about more than one multiplexed stream (like with audio
  272. playback). In that case, just maintain a flag for each
  273. decoder you care about, and pull data when any one of
  274. them stalls.
  275. videobuf_time holds the presentation time of the currently
  276. buffered video frame. We ignore this value.
  277. */
  278. stateflag=0; /* playback has not begun */
  279. /* queue any remaining pages from data we buffered but that did not
  280. contain headers */
  281. while(ogg_sync_pageout(&oy,&og)>0){
  282. queue_page(&og);
  283. }
  284. while(!got_sigint){
  285. while(theora_p && !videobuf_ready){
  286. /* theora is one in, one out... */
  287. if(ogg_stream_packetout(&to,&op)>0){
  288. theora_decode_packetin(&td,&op);
  289. videobuf_granulepos=td.granulepos;
  290. videobuf_time=theora_granule_time(&td,videobuf_granulepos);
  291. videobuf_ready=1;
  292. }else
  293. break;
  294. }
  295. if(!videobuf_ready && feof(infile))break;
  296. if(!videobuf_ready){
  297. /* no data yet for somebody. Grab another page */
  298. buffer_data(infile,&oy);
  299. while(ogg_sync_pageout(&oy,&og)>0){
  300. queue_page(&og);
  301. }
  302. }
  303. /* dumpvideo frame, and get new one */
  304. else video_write();
  305. videobuf_ready=0;
  306. }
  307. /* end of decoder loop -- close everything */
  308. if(theora_p){
  309. ogg_stream_clear(&to);
  310. theora_clear(&td);
  311. theora_comment_clear(&tc);
  312. theora_info_clear(&ti);
  313. }
  314. ogg_sync_clear(&oy);
  315. if(infile && infile!=stdin)fclose(infile);
  316. fprintf(stderr,
  317. "\r "
  318. "\nDone.\n");
  319. return(0);
  320. }