encoder_example.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*Daala video codec
  3. Copyright (c) 2006-2010 Daala project contributors. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. - Redistributions of source code must retain the above copyright notice, this
  7. list of conditions and the following disclaimer.
  8. - Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
  12. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  14. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  15. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  16. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  17. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  18. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  19. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  20. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <math.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <getopt.h>
  27. #include "../src/logging.h"
  28. #include "daala/daalaenc.h"
  29. #if defined(_WIN32)
  30. # include <fcntl.h>
  31. # include <io.h>
  32. #endif
  33. #if defined(_MSC_VER)
  34. static double rint(double _x){
  35. return (int)(_x<0?_x-0.5:_x+0.5);
  36. }
  37. #endif
  38. typedef struct av_input av_input;
  39. struct av_input{
  40. int has_video;
  41. FILE *video_infile;
  42. int video_pic_w;
  43. int video_pic_h;
  44. int video_fps_n;
  45. int video_fps_d;
  46. int video_par_n;
  47. int video_par_d;
  48. int video_interlacing;
  49. char video_chroma_type[16];
  50. int video_nplanes;
  51. daala_plane_info video_plane_info[OD_NPLANES_MAX];
  52. od_img video_img;
  53. int video_cur_img;
  54. };
  55. static int y4m_parse_tags(av_input *_avin,char *_tags){
  56. int got_w;
  57. int got_h;
  58. int got_fps;
  59. int got_interlacing;
  60. int got_par;
  61. int got_chroma;
  62. int tmp_video_fps_n;
  63. int tmp_video_fps_d;
  64. int tmp_video_par_n;
  65. int tmp_video_par_d;
  66. char *p;
  67. char *q;
  68. got_w=got_h=got_interlacing=got_chroma=0;
  69. got_fps=_avin->video_fps_n>0&&_avin->video_fps_d>0;
  70. got_par=_avin->video_par_n>=0&&_avin->video_par_d>=0;
  71. for(p=_tags;;p=q){
  72. /*Skip any leading spaces.*/
  73. while(*p==' ')p++;
  74. /*If that's all we have, stop.*/
  75. if(p[0]=='\0')break;
  76. /*Find the end of this tag.*/
  77. for(q=p+1;*q!='\0'&&*q!=' ';q++);
  78. /*Process the tag.*/
  79. switch(p[0]){
  80. case 'W':{
  81. if(sscanf(p+1,"%d",&_avin->video_pic_w)!=1)return -1;
  82. got_w=1;
  83. }break;
  84. case 'H':{
  85. if(sscanf(p+1,"%d",&_avin->video_pic_h)!=1)return -1;
  86. got_h=1;
  87. }break;
  88. case 'F':{
  89. if(sscanf(p+1,"%d:%d",&tmp_video_fps_n,&tmp_video_fps_d)!=2)return -1;
  90. got_fps=1;
  91. }break;
  92. case 'I':{
  93. _avin->video_interlacing=p[1];
  94. got_interlacing=1;
  95. }break;
  96. case 'A':{
  97. if(sscanf(p+1,"%d:%d",&tmp_video_par_n,&tmp_video_par_d)!=2)return -1;
  98. got_par=1;
  99. }break;
  100. case 'C':{
  101. if(q-p>16)return -1;
  102. memcpy(_avin->video_chroma_type,p+1,q-p-1);
  103. _avin->video_chroma_type[q-p-1]='\0';
  104. got_chroma=1;
  105. }break;
  106. /*Ignore unknown tags.*/
  107. }
  108. }
  109. if(!got_w||!got_h||!got_fps||!got_interlacing||!got_par)return -1;
  110. /*Chroma-type is not specified in older files, e.g., those generated by
  111. mplayer.*/
  112. if(!got_chroma)strcpy(_avin->video_chroma_type,"420");
  113. /*Update fps and aspect ration fields only if not specified on the command
  114. line.*/
  115. if(_avin->video_fps_n<=0||_avin->video_fps_d<=0){
  116. _avin->video_fps_n=tmp_video_fps_n;
  117. _avin->video_fps_d=tmp_video_fps_d;
  118. }
  119. if(_avin->video_par_n<0||_avin->video_par_d<0){
  120. _avin->video_par_n=tmp_video_par_n;
  121. _avin->video_par_d=tmp_video_par_d;
  122. }
  123. return 0;
  124. }
  125. static void id_y4m_file(av_input *_avin,const char *_file,FILE *_test){
  126. od_img *img;
  127. unsigned char buf[128];
  128. int ret;
  129. int pli;
  130. int bi;
  131. for(bi=0;bi<127;bi++){
  132. ret=fread(buf+bi,1,1,_test);
  133. if(ret<1)return;
  134. if(buf[bi]=='\n')break;
  135. }
  136. if(bi>=127){
  137. fprintf(stderr,"Error parsing '%s' header; not a YUV4MPEG2 file?\n",_file);
  138. exit(1);
  139. }
  140. buf[bi]='\0';
  141. if(memcmp(buf,"MPEG",4))return;
  142. if(buf[4]!='2'){
  143. fprintf(stderr,
  144. "Incorrect YUV input file version; YUV4MPEG2 required.\n");
  145. exit(1);
  146. }
  147. ret=y4m_parse_tags(_avin,(char *)buf+5);
  148. if(ret<0){
  149. fprintf(stderr,"Error parsing YUV4MPEG2 header fields in '%s'.\n",_file);
  150. exit(1);
  151. }
  152. if(_avin->video_interlacing!='p'){
  153. fprintf(stderr,"Interlaced input is not currently supported.\n");
  154. exit(1);
  155. }
  156. _avin->video_infile=_test;
  157. _avin->has_video=1;
  158. fprintf(stderr,"File '%s' is %ix%i %0.03f fps %s video.\n",
  159. _file,_avin->video_pic_w,_avin->video_pic_h,
  160. (double)_avin->video_fps_n/_avin->video_fps_d,_avin->video_chroma_type);
  161. /*Allocate buffers for the image data.*/
  162. /*TODO: Specify chroma offsets.*/
  163. _avin->video_plane_info[0].xdec=0;
  164. _avin->video_plane_info[0].ydec=0;
  165. if(strcmp(_avin->video_chroma_type,"444")==0){
  166. _avin->video_nplanes=3;
  167. _avin->video_plane_info[1].xdec=0;
  168. _avin->video_plane_info[1].ydec=0;
  169. _avin->video_plane_info[2].xdec=0;
  170. _avin->video_plane_info[2].ydec=0;
  171. }
  172. else if(strcmp(_avin->video_chroma_type,"444alpha")==0){
  173. _avin->video_nplanes=4;
  174. _avin->video_plane_info[1].xdec=0;
  175. _avin->video_plane_info[1].ydec=0;
  176. _avin->video_plane_info[2].xdec=0;
  177. _avin->video_plane_info[2].ydec=0;
  178. _avin->video_plane_info[3].xdec=0;
  179. _avin->video_plane_info[3].ydec=0;
  180. }
  181. else if(strcmp(_avin->video_chroma_type,"422")==0){
  182. _avin->video_nplanes=3;
  183. _avin->video_plane_info[1].xdec=1;
  184. _avin->video_plane_info[1].ydec=0;
  185. _avin->video_plane_info[2].xdec=1;
  186. _avin->video_plane_info[2].ydec=0;
  187. }
  188. else if(strcmp(_avin->video_chroma_type,"411")==0){
  189. _avin->video_nplanes=3;
  190. _avin->video_plane_info[1].xdec=2;
  191. _avin->video_plane_info[1].ydec=0;
  192. _avin->video_plane_info[2].xdec=2;
  193. _avin->video_plane_info[2].ydec=0;
  194. }
  195. else if(strcmp(_avin->video_chroma_type,"420")==0||
  196. strcmp(_avin->video_chroma_type,"420jpeg")==0){
  197. _avin->video_nplanes=3;
  198. _avin->video_plane_info[1].xdec=1;
  199. _avin->video_plane_info[1].ydec=1;
  200. _avin->video_plane_info[2].xdec=1;
  201. _avin->video_plane_info[2].ydec=1;
  202. }
  203. else if(strcmp(_avin->video_chroma_type,"420mpeg2")==0){
  204. _avin->video_nplanes=3;
  205. _avin->video_plane_info[1].xdec=1;
  206. _avin->video_plane_info[1].ydec=1;
  207. _avin->video_plane_info[2].xdec=1;
  208. _avin->video_plane_info[2].ydec=1;
  209. }
  210. else if(strcmp(_avin->video_chroma_type,"420paldv")==0){
  211. _avin->video_nplanes=3;
  212. _avin->video_plane_info[1].xdec=1;
  213. _avin->video_plane_info[1].ydec=1;
  214. _avin->video_plane_info[2].xdec=1;
  215. _avin->video_plane_info[2].ydec=1;
  216. }
  217. else if(strcmp(_avin->video_chroma_type,"mono")==0){
  218. _avin->video_nplanes=1;
  219. }
  220. else{
  221. fprintf(stderr,"Unknown chroma sampling type: '%s'.\n",
  222. _avin->video_chroma_type);
  223. exit(1);
  224. }
  225. img=&_avin->video_img;
  226. img->nplanes=_avin->video_nplanes;
  227. img->width=_avin->video_pic_w;
  228. img->height=_avin->video_pic_h;
  229. for(pli=0;pli<img->nplanes;pli++){
  230. od_img_plane *iplane;
  231. iplane=img->planes+pli;
  232. iplane->xdec=_avin->video_plane_info[pli].xdec;
  233. iplane->ydec=_avin->video_plane_info[pli].ydec;
  234. iplane->xstride=1;
  235. iplane->ystride=_avin->video_pic_w+(1<<iplane->xdec)-1>>iplane->xdec;
  236. iplane->data=_ogg_malloc(iplane->ystride*
  237. (_avin->video_pic_h+(1<<iplane->ydec)-1>>iplane->ydec));
  238. }
  239. }
  240. static void id_file(av_input *_avin,const char *_file){
  241. unsigned char buf[4];
  242. FILE *test;
  243. int ret;
  244. if(!strcmp(_file,"-"))test=stdin;
  245. else{
  246. test=fopen(_file,"rb");
  247. if(test==NULL){
  248. fprintf(stderr,"Unable to open input file '%s'\n",_file);
  249. exit(1);
  250. }
  251. }
  252. ret=fread(buf,1,4,test);
  253. if(ret<4){
  254. fprintf(stderr,"EOF determining file type of file '%s'\n",_file);
  255. exit(1);
  256. }
  257. if(!memcmp(buf,"YUV4",4)){
  258. if(_avin->has_video){
  259. fprintf(stderr,
  260. "Multiple YUV4MPEG2 files specified on the command line.\n");
  261. exit(1);
  262. }
  263. id_y4m_file(_avin,_file,test);
  264. if(!_avin->has_video){
  265. fprintf(stderr,"Error parsing YUV4MPEG2 file.\n");
  266. exit(1);
  267. }
  268. }
  269. else{
  270. fprintf(stderr,
  271. "Input file '%s' is neither a RIFF WAVE or YUV4MPEG2 file.\n",_file);
  272. }
  273. }
  274. int fetch_and_process_video(av_input *_avin,ogg_page *_page,
  275. ogg_stream_state *_vo,daala_enc_ctx *_dd,int _video_ready){
  276. ogg_packet op;
  277. while(!_video_ready){
  278. size_t ret;
  279. char frame[6];
  280. char c;
  281. int last;
  282. if(ogg_stream_pageout(_vo,_page)>0)return 1;
  283. else if(ogg_stream_eos(_vo))return 0;
  284. ret=fread(frame,1,6,_avin->video_infile);
  285. if(ret==6){
  286. od_img *img;
  287. int pli;
  288. if(memcmp(frame,"FRAME",5)!=0){
  289. fprintf(stderr,"Loss of framing in YUV input data.\n");
  290. exit(1);
  291. }
  292. if(frame[5]!='\n'){
  293. int bi;
  294. for(bi=0;bi<121;bi++){
  295. if(fread(&c,1,1,_avin->video_infile)==1&&c=='\n')break;
  296. }
  297. if(bi>=121){
  298. fprintf(stderr,"Error parsing YUV frame header.\n");
  299. exit(1);
  300. }
  301. }
  302. /*Read the frame data.*/
  303. img=&_avin->video_img;
  304. for(pli=0;pli<img->nplanes;pli++){
  305. od_img_plane *iplane;
  306. size_t plane_sz;
  307. iplane=img->planes+pli;
  308. plane_sz=(_avin->video_pic_w+(1<<iplane->xdec)-1>>iplane->xdec)*
  309. (_avin->video_pic_h+(1<<iplane->ydec)-1>>iplane->ydec);
  310. ret=fread(iplane->data/*+(_avin->video_pic_y>>iplane->ydec)*iplane->ystride+
  311. (_avin->video_pic_x>>iplane->xdec)*/,1,plane_sz,_avin->video_infile);
  312. if(ret!=plane_sz){
  313. fprintf(stderr,"Error reading YUV frame data.\n");
  314. exit(1);
  315. }
  316. }
  317. last=0;
  318. }
  319. else last=1;
  320. /*Pull the packets from the previous frame, now that we know whether or not
  321. we can read the current one.
  322. This is used to set the e_o_s bit on the final packet.*/
  323. while(daala_encode_packet_out(_dd,last,&op))ogg_stream_packetin(_vo,&op);
  324. /*Submit the current frame for encoding.*/
  325. if(!last)daala_encode_img_in(_dd,&_avin->video_img,0);
  326. }
  327. return _video_ready;
  328. }
  329. static const char *OPTSTRING="o:a:A:v:V:s:S:f:F:h:k:";
  330. static const struct option OPTIONS[]={
  331. {"output",required_argument,NULL,'o'},
  332. {"video-quality",required_argument,NULL,'v'},
  333. {"video-rate-target",required_argument,NULL,'V'},
  334. {"keyframe-rate",required_argument,NULL,'k'},
  335. {"aspect-numerator",optional_argument,NULL,'s'},
  336. {"aspect-denominator",optional_argument,NULL,'S'},
  337. {"framerate-numerator",optional_argument,NULL,'f'},
  338. {"framerate-denominator",optional_argument,NULL,'F'},
  339. {"help",no_argument,NULL,'h'},
  340. {NULL,0,NULL,0}
  341. };
  342. static void usage(void){
  343. fprintf(stderr,
  344. "Usage: encoder_example [options] video_file\n\n"
  345. "Options:\n\n"
  346. " -o --output <filename.ogg> file name for encoded output;\n"
  347. " If this option is not given, the\n"
  348. " compressed data is sent to stdout.\n\n"
  349. " -v --video-quality <n> Daala quality selector from 0 to 10.\n"
  350. " 0 yields the smallest files, but\n"
  351. " lowest video quality; 10 yields the\n"
  352. " highest quality, but large files.\n\n"
  353. " -k --keyframe-rate <n> Fequence of keyframes in output.\n\n"
  354. " -V --video-rate-target <n> bitrate target for Daala video;\n"
  355. " use -v and not -V if at all possible,\n"
  356. " as -v gives higher quality for a given\n"
  357. " bitrate.\n\n"
  358. " encoder_example accepts only uncompressed YUV4MPEG2 video.\n\n");
  359. exit(1);
  360. }
  361. int main(int _argc,char **_argv){
  362. FILE *outfile;
  363. av_input avin;
  364. ogg_stream_state vo;
  365. ogg_page og;
  366. ogg_packet op;
  367. daala_enc_ctx *dd;
  368. daala_info di;
  369. daala_comment dc;
  370. ogg_int64_t video_bytesout;
  371. double time_base;
  372. int c;
  373. int loi;
  374. int ret;
  375. int video_kbps;
  376. int video_q;
  377. int video_r;
  378. int video_keyframe_rate;
  379. int video_ready;
  380. int pli;
  381. od_log_init(NULL);
  382. #if defined(_WIN32)
  383. _setmode(_fileno(stdin),_O_BINARY);
  384. _setmode(_fileno(stdout),_O_BINARY);
  385. #endif
  386. outfile=stdout;
  387. memset(&avin,0,sizeof(avin));
  388. avin.video_fps_n=-1;
  389. avin.video_fps_d=-1;
  390. avin.video_par_n=-1;
  391. avin.video_par_d=-1;
  392. video_q=48;
  393. video_keyframe_rate=1; /* TODO - default off for now but make bigger later */
  394. video_r=-1;
  395. video_bytesout=0;
  396. video_kbps=0;
  397. while((c=getopt_long(_argc,_argv,OPTSTRING,OPTIONS,&loi))!=EOF){
  398. switch(c){
  399. case 'o':{
  400. outfile=fopen(optarg,"wb");
  401. if(outfile==NULL){
  402. fprintf(stderr,"Unable to open output file '%s'\n",optarg);
  403. exit(1);
  404. }
  405. }break;
  406. case 'k':{
  407. video_keyframe_rate=atoi(optarg);
  408. if(video_keyframe_rate<1||video_keyframe_rate>1000){
  409. fprintf(stderr,"Illegal video keyframe rate (use 1 through 1000)\n");
  410. exit(1);
  411. }
  412. }break;
  413. case 'v':{
  414. video_q=(int)rint(atof(optarg)*6.3);
  415. if(video_q<0||video_q>63){
  416. fprintf(stderr,"Illegal video quality (use 0 through 10)\n");
  417. exit(1);
  418. }
  419. video_r=0;
  420. }break;
  421. case 'V':{
  422. video_r=(int)rint(atof(optarg)*1000);
  423. if(video_r<45000||video_r>2000000){
  424. fprintf(stderr,
  425. "Illegal video bitrate (use 45kbps through 2000kbps)\n");
  426. exit(1);
  427. }
  428. video_q=0;
  429. }break;
  430. case 'h':
  431. default:{
  432. usage();
  433. }
  434. }
  435. }
  436. /*Assume anything following the options must be a file name.*/
  437. for(;optind<_argc;optind++)id_file(&avin,_argv[optind]);
  438. if(!avin.has_video){
  439. fprintf(stderr,"No video files submitted for compression.\n");
  440. exit(1);
  441. }
  442. srand(time(NULL));
  443. ogg_stream_init(&vo,rand());
  444. daala_info_init(&di);
  445. di.pic_width=avin.video_pic_w;
  446. di.pic_height=avin.video_pic_h;
  447. di.timebase_numerator=avin.video_fps_n;
  448. di.timebase_denominator=avin.video_fps_d;
  449. di.frame_duration=1;
  450. di.pixel_aspect_numerator=avin.video_par_n;
  451. di.pixel_aspect_denominator=avin.video_par_d;
  452. di.nplanes=avin.video_nplanes;
  453. memcpy(di.plane_info,avin.video_plane_info,
  454. di.nplanes*sizeof(*di.plane_info));
  455. di.keyframe_rate = video_keyframe_rate;
  456. /*TODO: Other crap.*/
  457. dd=daala_encode_create(&di);
  458. daala_comment_init(&dc);
  459. /*TODO: Set up encoder.*/
  460. /*Write the bitstream header packets with proper page interleave.*/
  461. /*The first packet for each logical stream will get its own page
  462. automatically.*/
  463. if(daala_encode_flush_header(dd,&dc,&op)<=0){
  464. fprintf(stderr,"Internal Daala library error.\n");
  465. exit(1);
  466. }
  467. ogg_stream_packetin(&vo,&op);
  468. if(ogg_stream_pageout(&vo,&og)!=1){
  469. fprintf(stderr,"Internal Ogg library error.\n");
  470. exit(1);
  471. }
  472. fwrite(og.header,1,og.header_len,outfile);
  473. fwrite(og.body,1,og.body_len,outfile);
  474. /*Create and buffer the remaining Daala headers.*/
  475. for(;;){
  476. ret=daala_encode_flush_header(dd,&dc,&op);
  477. if(ret<0){
  478. fprintf(stderr,"Internal Daala library error.\n");
  479. exit(1);
  480. }
  481. else if(!ret)break;
  482. ogg_stream_packetin(&vo,&op);
  483. }
  484. for(;;){
  485. ret=ogg_stream_flush(&vo,&og);
  486. if(ret<0){
  487. fprintf(stderr,"Internal Ogg library error.\n");
  488. exit(1);
  489. }
  490. else if(!ret)break;
  491. fwrite(og.header,1,og.header_len,outfile);
  492. fwrite(og.body,1,og.body_len,outfile);
  493. }
  494. /*Setup complete.
  495. Main compression loop.*/
  496. fprintf(stderr,"Compressing...\n");
  497. video_ready=0;
  498. for(;;){
  499. ogg_page video_page;
  500. double video_time;
  501. video_ready=fetch_and_process_video(&avin,&video_page,
  502. &vo,dd,video_ready);
  503. /*TODO: Fetch the next video page.*/
  504. /*If no more pages are available, we've hit the end of the stream.*/
  505. if(!video_ready)break;
  506. video_time=video_ready?
  507. daala_granule_time(dd,ogg_page_granulepos(&video_page)):-1;
  508. video_bytesout+=
  509. fwrite(video_page.header,1,video_page.header_len,outfile);
  510. video_bytesout+=fwrite(video_page.body,1,video_page.body_len,outfile);
  511. video_ready=0;
  512. video_kbps=(int)rint(video_bytesout*8*0.001/video_time);
  513. time_base=video_time;
  514. fprintf(stderr,
  515. "\r %i:%02i:%02i.%02i video: %ikbps ",
  516. (int)time_base/3600,((int)time_base/60)%60,(int)time_base%60,
  517. (int)(time_base*100-(long)time_base*100),video_kbps);
  518. }
  519. ogg_stream_clear(&vo);
  520. daala_encode_free(dd);
  521. daala_comment_clear(&dc);
  522. for(pli=0;pli<avin.video_img.nplanes;pli++){
  523. _ogg_free(avin.video_img.planes[pli].data);
  524. }
  525. if(outfile!=NULL&&outfile!=stdout)fclose(outfile);
  526. fprintf(stderr,"\r \ndone.\n\r");
  527. if(avin.video_infile!=NULL&&avin.video_infile!=stdin){
  528. fclose(avin.video_infile);
  529. }
  530. return 0;
  531. }