mpeg2video.cc
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:10k
源码类别:

DVD

开发平台:

Unix_Linux

  1. /*
  2.    File: mpeg2video.cc
  3.    By: Alex Theo de Jong
  4.    Created: February 1996
  5.    Description:
  6.    Implementation of the MPEG 2 Video class
  7. */
  8. #define RELEASE "1.2, November 1996"
  9. #ifdef __GNUG__
  10. #pragma implementation
  11. #endif
  12. #include "athread.hh"
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <ctype.h>
  16. #include <String.h>
  17. #include <fstream.h>
  18. #ifdef USE_OPENPTC
  19. #include <ptc/ptc.h>
  20. #endif
  21. #include "error.hh"
  22. #include "debug.hh"
  23. #include "util.hh"
  24. #include "sync.hh"
  25. #include "mpeg2const.hh"
  26. #include "mpeg2buff.hh"
  27. #include "videoconst.hh"
  28. #include "display.hh"
  29. #include "idct.hh"
  30. #include "vstream.hh"
  31. #include "layerdata.hh"
  32. #define GLOBAL
  33. #include "global.hh"
  34. #include "mpeg2video.hh"
  35. /*
  36.  *
  37.  * Mpeg2Video
  38.  *
  39.  */
  40. int error=0;
  41. Mpeg2Video::Mpeg2Video(Mpeg2Buffer* input_buffer, Synchronization* s, int c, char** v) :
  42.   argc(c), terminate(0), terminated(0), blockreadsize(0), framerate(0), 
  43.   skip_state(0), skip_count(0), skipped_frames(0) 
  44. {
  45.   if (argc) argv=v;
  46.   else argv=0;
  47.   if (options()){   // parse options
  48.     // create layer data (including display)
  49.     ::ld=new LayerData(displaytitle.chars(), s);
  50.     
  51.     // set or create video data buffer
  52.     if (input_buffer) ld->input=new VideoStream(input_buffer, s);
  53.     else ld->input=0;
  54.     
  55.     // start player thread
  56.     if ((error=athr_create((void*(*)(void*))Mpeg2Video::player, this, &thread_id))<0){
  57.       error("could not create video player");
  58.       athr_exit(0);
  59.     }
  60.     
  61.     /* Seem to slow things donw! */
  62.     sched_param param;
  63.     int policy;
  64.     if (athr_getschedparam(thread_id, &policy , &param)<0){
  65.       error("could not get thread priority");
  66.     }
  67. #ifdef LINUX
  68.     param.sched_priority+=1;
  69. //    policy = SCHED_RR;
  70.     TRACER("VIDEOPRIORITY=" << param.sched_priority << "(" << param.sched_priority-2 << ")");
  71. #else
  72.     param.prio+=2;
  73.     TRACER("VIDEOPRIORITY=" << param.prio << "(" << param.prio-2 << ")");
  74. #endif
  75.     if (athr_setschedparam(thread_id, policy, &param)<0){
  76.       error("could not set thread priority");
  77.     }
  78.   }
  79. }
  80. Mpeg2Video::~Mpeg2Video(){
  81.   terminate=1;
  82.   if (!terminated){
  83.     TRACER("waiting for video thread to terminate ... ");
  84.     athr_join(thread_id);
  85.   }
  86. #if 0
  87.   delete ::ld;
  88.   delete llframe1[0];
  89.   delete lltmp;
  90.   for (int i=0; i<3; i++){
  91.     delete auxframe[i];
  92.     delete refframe[i];
  93.     delete oldrefframe[i];
  94. //    delete llframe1[0];
  95. //    delete lltmp;
  96.   }
  97. #endif
  98.   TRACER("video thread terminated");
  99. }
  100. void* Mpeg2Video::player(Mpeg2Video* base){
  101.   base->terminate=0;
  102.   base->terminated=0;
  103.   base->play();
  104.   base->terminated=1;
  105.   athr_exit(0);
  106.   return 0;
  107. }
  108. const int NBR_FRAMES = 100;
  109. Mpeg2Video* mv=0;
  110. int Mpeg2Video::play(){
  111.   TRACER("int Mpeg2Video::play()");
  112.   timeval tstart;  // Time start
  113.   timeval sstart;  // Sequence of NBR_FRAMES start
  114.   timeval fstart, fstop; // Frame start and stop
  115. //verbose=2;
  116.   framenum=0;
  117.   skip_state=0;
  118.   skip_count=0;
  119.   skipped_frames=0;
  120.   i_c=p_c=b_c=d_c=0;
  121.   if (!ld->input) 
  122.     ld->input=new VideoStream(filename.chars()); // read from file
  123.   if (blockreadsize)
  124.     ld->input->set_read_block_size(blockreadsize);
  125.   ::vs=ld->input;
  126.   while (!terminate && ld->getheader() && (!ld->sync || !ld->sync->done(1))){ 
  127.     if (!framenum){
  128.       initdecoder();
  129.       gettimeofday(&tstart, 0);
  130.       gettimeofday(&sstart, 0);
  131.       gettimeofday(&fstart, 0);
  132.     }
  133.     playedlastframe=0;
  134.     
  135.     // Allow B-frames to be skipped if in "skip_state"
  136.     switch(pict_type){
  137.     case B_TYPE : b_c++; if (skip_state<=0) ld->getpicture(framenum); else skipped_frames++; break;
  138.     case P_TYPE : p_c++; ld->getpicture(framenum); break;
  139.     case I_TYPE : i_c++; ld->getpicture(framenum); break;
  140.     case D_TYPE : d_c++; if (!skip_state) ld->getpicture(framenum); else skipped_frames++; break;
  141.     default     :  error("unknown frame in video stream");
  142.     }
  143.     framenum++;  // cruzial to have this here!!
  144.     athr_yield();
  145.     if (!secondfield){
  146.       if (ld->sync && !playedlastframe) 
  147.         if (ld->sync->skip(1)<0) break;  // skip PTS, <0 end of file
  148.       if (framerate!=0){
  149.         gettimeofday(&fstop, 0);
  150.         doframerate(fstart, fstop);
  151.         gettimeofday(&fstart, 0);
  152.       }
  153.     }
  154.     if (!quiet && framenum>1 && (framenum % NBR_FRAMES)==0){
  155.       showframerate(sstart);
  156.       gettimeofday(&sstart, 0);
  157.     }
  158.   }
  159.   if (framenum!=0) ld->putlast();   // put last frame
  160.   if (!quiet && framenum) showframerateend(tstart);
  161.   return 0;
  162. }
  163. void Mpeg2Video::doframerate(timeval& fstart, timeval& fstop){
  164.   int time_real_usec=
  165.     (fstop.tv_sec-fstart.tv_sec)*1000000+(fstop.tv_usec-fstart.tv_usec);
  166.   if (time_real_usec > time_interval_usec){
  167.     if (++skip_count>0) skip_state=1;  // Running behind
  168.     return;
  169.   }
  170.   else {                               // Running ahead
  171.     if (--skip_count<-2){
  172.       skip_state=0;
  173. //      timer.waitcond(time_interval_usec - time_real_usec);
  174.       timer.wait(time_interval_usec - time_real_usec);
  175.     }
  176.     return;
  177.   }
  178. }
  179. int Mpeg2Video::showframerate(timeval& sstart){  // show frame rate every NBR_FRAMES frames
  180.   static char txt[100];
  181.   timeval tstop;
  182.   gettimeofday(&tstop,(struct timezone *)NULL);
  183.   unsigned int runtime=1000*(tstop.tv_sec-sstart.tv_sec)+(tstop.tv_usec-sstart.tv_usec)/1000;
  184.   sprintf(txt, " %d.%02d fps ", (1000*NBR_FRAMES/runtime), ((100000*NBR_FRAMES/runtime)%100));
  185.   msg(txt);
  186.   return 1;
  187. }
  188. int Mpeg2Video::showframerateend(timeval& tstart){
  189.   static char txt[100];
  190.   timeval tstop;
  191.   gettimeofday(&tstop,(struct timezone *)NULL);
  192.   int runtime = 1000*(tstop.tv_sec-tstart.tv_sec)+(tstop.tv_usec-tstart.tv_usec)/1000;
  193. /*
  194.   sprintf(errortext, "n%d.%02d seconds, %d frames, %d.%02d fps (%d B frames skipped)",
  195.           runtime/100, runtime%100, framenum, ((10000*framenum+runtime/2)/runtime)/100,
  196.           ((10000*framenum+runtime/2)/runtime)%100, skipped_frames);
  197. */
  198.   sprintf(txt, "n%d.%02d seconds, %d frames, %d.%02d fps (%d B frames skipped)",
  199.           runtime/1000, (100*runtime/1000)%100, framenum, 1000*framenum/runtime,
  200.           (100000*framenum/runtime)%100, skipped_frames);
  201.   message(txt);
  202.   sprintf(txt, "Frames: %d (I), %d (P), %d (B), %d (D)", i_c, p_c, b_c, d_c);
  203.   message(txt);
  204.   return 1;
  205. }
  206. void Mpeg2Video::usage(const char* name){
  207.   msg("usage: "); msg(name); message("[options]");
  208.   message("options:");
  209.   message("t-f <s>tFilename <s> (required)");
  210.   message("t-v <n>tverbose output (n: level)");
  211.   message("t-qtquiet (no error output)");
  212.   message("t-d <s>tdisplay title (s: title)");
  213.   message("t-fr <n>tframe rate (default = as fast as possible)"); 
  214.   message("t-c <n>tChunk size for buffer block read (NOTE: be carefull when using sychronization)");
  215.   message("");
  216.   message("tMPEG 2 Video Playern");
  217.   msg("tversion "); message(RELEASE);
  218.   message("tAlex Theo de Jong (e-mail: alex.dejong@nist.gov)n");
  219.   message("tMulti-Media and Digital Video Group");
  220.   message("tNational Institute of Standards and Technology");
  221.   message("tGaithersburg, Md, U.S.A.nn");
  222.   message("");
  223.   message("Original code by:");
  224.   message("tMPEG Software Simulation Group   &");
  225.   message("tStefan Eckart");
  226.   message("tFraunhofer-Institut fuer Festkoerpertechnologie, Germany");
  227. }
  228. int Mpeg2Video::options(){
  229.   TRACER("int Mpeg2Video::options()");
  230.   if (argc<3){
  231.     usage(argv[0]);
  232.     return 0;
  233.   }
  234.   for (int i=1; i<argc; i++){
  235.     if (strcmp(argv[i], "-f") == 0 && (i+1)<argc) filename=argv[++i];
  236. // general options
  237.     else if (strcmp(argv[i], "-v") == 0 && (i+1)<argc) verbose=atoi(argv[++i]);
  238.     else if (strcmp(argv[i], "-fr") == 0 && (i+1)<argc) ::framerate=atoi(argv[++i]);
  239. #ifdef TRACE
  240.     else if (strcmp(argv[i], "-t") == 0) trace=1;
  241. #endif
  242.     else if (strcmp(argv[i], "-d") == 0 && (i+1)<argc) displaytitle=argv[++i];
  243.     else if (strcmp(argv[i], "-c") == 0 && (i+1)<argc) blockreadsize=atoi(argv[++i]);
  244.     else if (strcmp(argv[i], "-q") == 0) quiet=1;
  245.     else {
  246.     message("unknown argument `"); message(argv[i]); message("` - ignored");
  247.     }
  248.   }
  249.   if (framerate)
  250.     time_interval_usec=1000000/framerate;  // in usec
  251.   if (!displaytitle.length()) 
  252.     displaytitle="Hi there!";
  253.   return 1;
  254. }
  255. int Mpeg2Video::initdecoder(){
  256.   TRACER("int Mpeg2Video::initdecoder()");
  257.   int size;
  258.   static int blk_cnt_tab[3] = {6,8,12};
  259.   if (!ld->mpeg2){     // force MPEG-1 parameters
  260.     prog_seq = 1;
  261.     prog_frame = 1;
  262.     pict_struct = FRAME_PICTURE;
  263.     frame_pred_dct = 1;
  264.     chroma_format = CHROMA420;
  265.     matrix_coefficients = 5;
  266.   }
  267.   /* round to nearest multiple of coded macroblocks */
  268.   mb_width = (horizontal_size+15)/16;
  269.   mb_height = (ld->mpeg2 && !prog_seq) ? 2*((vertical_size+31)/32)
  270.                                         : (vertical_size+15)/16;
  271.   coded_picture_width = 16*mb_width;
  272.   coded_picture_height = 16*mb_height;
  273.   chrom_width = (chroma_format==CHROMA444) ? coded_picture_width
  274.                                            : coded_picture_width>>1;
  275.   chrom_height = (chroma_format!=CHROMA420) ? coded_picture_height
  276.                                             : coded_picture_height>>1;
  277.   blk_cnt = blk_cnt_tab[chroma_format-1];
  278.   for (int cc=0; cc<3; cc++){
  279.     if (cc==0) size = coded_picture_width*coded_picture_height;
  280.     else       size = chrom_width*chrom_height;
  281.     refframe[cc]=new unsigned char[size];
  282.     oldrefframe[cc]=new unsigned char[size];
  283.     auxframe[cc]=new unsigned char[size];
  284.     if (ld->scalable_mode==SC_SPAT){   // this assumes lower layer is 4:2:0
  285.       llframe0[cc]=new unsigned char[(llw*llh)/(cc?4:1)];
  286.       llframe1[cc]=new unsigned char[(llw*llh)/(cc?4:1)];
  287.     }
  288.   }
  289.   if (ld->scalable_mode==SC_SPAT) lltmp=new short[llw*((llh*vn)/vm)];
  290.   //if (!ld->display || (ld->display->init(coded_picture_width, coded_picture_height,1,5,48*1,57*5,100,576-100)<0)){
  291.   if (!ld->display || (ld->display->init(coded_picture_width, coded_picture_height,1,1,1,1,0,0)<0)){
  292.      error("could not initialize X11 display");
  293.     athr_exit(0);
  294.   }
  295.   return 1;
  296. }