home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 June / ccd0605.iso / LINUX / gopchop-1.1.7.tar.tar / gopchop-1.1.7.tar / gopchop-1.1.7 / src / GOPutils.cpp < prev    next >
C/C++ Source or Header  |  2005-04-30  |  14KB  |  475 lines

  1. /*
  2. #
  3. # Worker for writing GOP information to files
  4. #
  5. # $Id: GOPutils.cpp,v 1.9 2005/04/30 20:10:01 keescook Exp $
  6. #
  7. # Copyright (C) 2003 Kees Cook
  8. # kees@outflux.net, http://outflux.net/
  9. # This program is free software; you can redistribute it and/or
  10. # modify it under the terms of the GNU General Public License
  11. # as published by the Free Software Foundation; either version 2
  12. # of the License, or (at your option) any later version.
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. # GNU General Public License for more details.
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20. # http://www.gnu.org/copyleft/gpl.html
  21. #
  22. */
  23.  
  24. #include "GOPchop.h"
  25. #include "GOPutils.h"
  26.  
  27. #include "MPEG2Parser.h"
  28. #include "Picture.h"
  29.  
  30. // display writing locations (from write_GOP) to stderr
  31. #undef MPEG2_CLIPS_TO_STDERR
  32.  
  33. #include "mpeg2consts.h"
  34. void write_timestamp(unsigned char * head, uint32_t pictures, int rate);
  35.  
  36. /*
  37.  * This exports a text file that can be used to re-load an MPEG2-PS
  38.  * much more quickly.  (And this file can be used to check the results
  39.  * of GOPchop's parser.)
  40.  *
  41.  * Format is:
  42.  *   TAG COUNT OFFSET[:LENGTH]
  43.  *
  44.  * GOP %u %llu:%lu
  45.  * pack %u %llu
  46.  * ...
  47.  * pic %u %llu:%lu
  48.  * ves %u %llu:%lu
  49.  * ...
  50.  *
  51.  * If you have more GOPs than can be indexed by a 32bit variable,
  52.  * then you can change the index variable yourself.  ;)
  53.  *
  54.  */
  55. int write_gop_cache(char * filename, MPEG2Parser * mpeg2parser)
  56. {
  57.     int result=-1;
  58.     List *GOPs;
  59.     List *packets;
  60.     List *pictures;
  61.     List *ves;
  62.     Vector *vector;
  63.     uint32_t gopnum, gopmax;
  64.     FILE * fp;
  65.  
  66.     if (!(fp=fopen(filename,"w"))) {
  67.         perror(filename);
  68.         return -1;
  69.     }
  70.  
  71.     if (!(GOPs = mpeg2parser->getGOPs())) {
  72.         printf("%s",_("NULL GOP list?!\n"));
  73.         goto need_close;
  74.     }
  75.     if (!(packets = mpeg2parser->getPackets())) {
  76.         printf("%s", _("NULL packet list?!\n"));
  77.         goto need_close;
  78.     }
  79.     if (!(pictures = mpeg2parser->getPictures())) {
  80.         printf("%s", _("NULL picture list?!\n"));
  81.         goto need_close;
  82.     }
  83.     if (!(ves = mpeg2parser->getVideo())) {
  84.         printf("%s", _("NULL VES list?!\n"));
  85.         goto need_close;
  86.     }
  87.  
  88.     gopmax=GOPs->getNum();
  89.     for (gopnum=0;gopnum<gopmax;gopnum++) {
  90.         GroupOfPictures *gop;
  91.         Bounds *bounds;
  92.         uint32_t num, max;
  93.         Vector *header;
  94.  
  95.         if (!(gop=(GroupOfPictures*)GOPs->vector(gopnum))) {
  96.             printf("%s", _("Missing GOP %u!?\n"),gopnum);
  97.             goto need_close;
  98.         }
  99.  
  100.         if (!(header=gop->getHeader())) {
  101.             printf("%s",_("Missing GOP %u header!?\n"),gopnum);
  102.             goto need_close;
  103.         }
  104.  
  105.         fprintf(fp,"GOP %u %" OFF_T_FORMAT "\n",
  106.                    gopnum, header->getStart());
  107.  
  108.         /* report packets */
  109.         if (!(bounds=gop->getPacketBounds())) {
  110.             printf("%s", _("NULL packet list for GOP %d?!\n"), gopnum);
  111.             goto need_close;
  112.         }
  113.         max=bounds->getMax();
  114.         for (num=bounds->getFirst();num<max;num++) {
  115.             Pack *pack;
  116.  
  117.             if (!(pack=(Pack*)packets->vector(num))) {
  118.                 printf("%s",_("Missing Pack %u!?\n"),num);
  119.                 goto need_close;
  120.             }
  121.  
  122.             fprintf(fp,"pack %u %" OFF_T_FORMAT "\n",
  123.                        num, pack->getStart());
  124.             
  125.         }
  126.  
  127.         /* report pictures */
  128.         if (!(bounds=gop->getPictureBounds())) {
  129.             printf("%s", _("NULL picture list for GOP %d?!\n"), gopnum);
  130.             goto need_close;
  131.         }
  132.         max=bounds->getMax();
  133.         for (num=bounds->getFirst();num<max;num++) {
  134.             Picture *picture;
  135.             Bounds * vesbounds;
  136.             uint32_t vesnum, vesmax;
  137.  
  138.             if (!(picture=(Picture*)pictures->vector(num))) {
  139.                 printf("%s",_("Missing Picture %u!?\n"),num);
  140.                 goto need_close;
  141.             }
  142.  
  143.             fprintf(fp,"pic %u %" OFF_T_FORMAT "\n",
  144.                        num,picture->getStart());
  145.  
  146.             /* report video */
  147.             if (!(vesbounds=picture->getVideoBounds())) {
  148.                 printf("%s", _("NULL video ES list for GOP %d?!\n"), gopnum);
  149.                 goto need_close;
  150.             }
  151.             vesmax=vesbounds->getMax();
  152.             for (vesnum=vesbounds->getFirst();vesnum<vesmax;vesnum++) {
  153.                 ElementStream *es;
  154.  
  155.                 if (!(es=(ElementStream*)ves->vector(vesnum))) {
  156.                     printf("%s",_("Missing VES packet %u!?\n"),vesnum);
  157.                     goto need_close;
  158.                 }
  159.  
  160.                 fprintf(fp,"ves %u %" OFF_T_FORMAT ":%lu\n",
  161.                            vesnum,es->getStart(),es->getLen());
  162.             }
  163.         }
  164.     }
  165.  
  166.     result=0;
  167.  
  168. need_close:
  169.     if (fclose(fp)) {
  170.         perror(filename);
  171.         result=-1;
  172.     }
  173.     return result;
  174. }
  175.  
  176. void write_clip_list(char * filename, struct clip_list_t * clips)
  177. {
  178. }
  179.  
  180. /*
  181.  * Global memory area to do GOPheader manipulations
  182.  */
  183. uint8_t * GOPareaPtr = NULL;
  184. size_t GOPareaSize = 0;
  185. /*
  186.  * file: stream to write to
  187.  * mpeg2parser: object to read MPEG2 data from
  188.  * num: which GOP to write
  189.  * continuous: was the GOP before this one the "original" prior GOP?
  190.  * drop_orphaned_frames: should non-continuous orphaned B/P frames get dropped?
  191.  * adjust_timestamps: should timestamps be updated?
  192.  * pictures_written: pointer to read/update number of pictures written
  193.  *
  194.  */
  195. off_t write_GOP(FILE * file, MPEG2Parser * mpeg2parser,
  196.                 uint32_t num, int continuous,
  197.                 int drop_orphaned_frames,
  198.                 int adjust_timestamps,
  199.                 uint32_t *pictures_written,
  200.                 bool is_last_gop,
  201.                 bool drop_trailing_pack_with_system_header
  202.                 )
  203. {
  204.     List *GOPs;
  205.     GroupOfPictures *GOP;
  206.     Vector *GOPheader;
  207.     List *packets;
  208.     Bounds *packet_bounds;
  209.     Bounds *picture_bounds;
  210.     Vector *pes_vector;
  211.     Pack *packet;
  212.     uint32_t pes, pes_max;
  213.     uint8_t old_bits;
  214.     uint8_t *header;
  215.     uint8_t *area;
  216.     int P_Frame_seen;
  217.     int open_GOP;
  218.  
  219.     off_t written_bytes;
  220.     uint32_t written_pictures;
  221.  
  222.     size_t GOPlen;
  223.     size_t GOPoffset;
  224.  
  225.  
  226.     written_bytes = 0;
  227.     written_pictures = 0;
  228.     P_Frame_seen = 0;
  229.     open_GOP = 0;
  230.  
  231.     if (!mpeg2parser || !file) return 0;
  232.  
  233.     if (!(GOPs = mpeg2parser->getGOPs())) {
  234.         printf("%s", _("NULL GOP list?!\n"));
  235.         return 0;
  236.     }
  237.     if (!(packets = mpeg2parser->getPackets())) {
  238.         printf("%s", _("NULL packet list?!\n"));
  239.         return 0;
  240.     }
  241.     if (!(GOP = (GroupOfPictures *) GOPs->vector(num))) {
  242.         printf("%s", _("NULL GOP?!\n"));
  243.         return 0;
  244.     }
  245.     if (!(GOPheader = (Vector *) GOP->getHeader())) {
  246.         printf("%s", _("NULL GOP header?!\n"));
  247.         return 0;
  248.     }
  249.     if (!(packet_bounds = GOP->getPacketBounds())) {
  250.         printf("%s", _("NULL packet bounds?!\n"));
  251.         return 0;
  252.     }
  253.  
  254.     // figure out how many pictures we're going to write
  255.     if (!(picture_bounds = GOP->getPictureBounds())) {
  256.         printf("%s", _("NULL GOP picture bounds?!\n"));
  257.         return 0;
  258.     }
  259.     written_pictures = picture_bounds->getMax() - picture_bounds->getFirst();
  260.  
  261.     // instead of writing one packet at a time, let's try
  262.     // writing whole GOPs at once.
  263.  
  264.     // figure out size of GOP in memory
  265.     GOPlen = 0;
  266.     pes_max = packet_bounds->getMax();
  267.     
  268.     /* TI! */
  269.     if (drop_trailing_pack_with_system_header &&
  270.         is_last_gop) //check if the last pack has a system header
  271.     {
  272.         Pack *last_packet = (Pack *) packets->vector(pes_max - 1);  //last packet
  273.         
  274.         pack_header_t *pk_header = (pack_header_t *)mpeg2parser->bytesAvail(last_packet->getStart(), sizeof(pack_header_t));
  275.         
  276.         //is it here the system header?
  277.         off_t addr_system_header= last_packet->getStart() + sizeof(pack_header_t) + (pk_header->bits[9] & 0x07);
  278.         //printf("addr_system_header [%lu]\n",(unsigned long) addr_system_header);
  279.         
  280.         system_header_t *sys_header = (system_header_t *)
  281.             mpeg2parser->bytesAvail(addr_system_header, sizeof(system_header_t));
  282.         
  283.         if (sys_header->start_code[0]==0x00 &&
  284.             sys_header->start_code[1]==0x00 &&
  285.             sys_header->start_code[2]==0x01 &&
  286.             sys_header->start_code[3]==0xBB)
  287.         {    
  288.             //printf("Found system header in Last Pack\n");
  289.             pes_max--;
  290.         }
  291.     }
  292.     /* end TI! */
  293.     
  294.     for (pes = packet_bounds->getFirst(); pes < pes_max; pes++)
  295.     {
  296.         if (!(packet = (Pack *) packets->vector(pes)))
  297.         {
  298.             printf("%s", _("NULL PES?!\n"));
  299.             return 0;
  300.         }
  301.         GOPlen += packet->getLen();
  302.     }
  303.     if (GOPlen > GOPareaSize)
  304.     {
  305.         // let's not realloc because we don't need to keep the
  306.         // contents
  307.         if (GOPareaPtr)
  308.             free(GOPareaPtr);
  309.         if (!(GOPareaPtr = (uint8_t *) malloc(GOPlen)))
  310.         {
  311.             printf("%s", _("Ran out of memory!?\n"));
  312.             return 0;
  313.         }
  314.         GOPareaSize = GOPlen;
  315.     }
  316.  
  317.     GOPoffset = 0;
  318.     //pes_max = packet_bounds->getMax(); //TI!
  319.     for (pes = packet_bounds->getFirst(); pes < pes_max; pes++)
  320.     {
  321.         size_t len;
  322.         int undo;
  323.         int okay_to_write;
  324.         int has_header;
  325.  
  326.         // assume we can write this packet...
  327.         okay_to_write = 1;
  328.         has_header = 0;
  329.         //printf("writing PES %d\n",pes);
  330.  
  331.         if (!(packet = (Pack *) packets->vector(pes)))
  332.         {
  333.             printf("%s", _("NULL PES?!\n"));
  334.             goto abort;
  335.         }
  336.  
  337.         len = packet->getLen();
  338.         if (!(area = mpeg2parser->bytesAvail(packet->getStart(), len)))
  339.         {
  340.             printf("%s", _("unavailable memory?!\n"));
  341.             goto abort;
  342.         }
  343.  
  344.         // do our header verifications in mmap, but make the
  345.         // actual changes in our shared memory area
  346.         if (GOPheader->getStart() > packet->getStart() &&
  347.             GOPheader->getStart() + GOPheader->getLen() <
  348.             packet->getStart() + packet->getLen())
  349.         {
  350.             // GOP header is in this packet
  351.             has_header = 1;
  352.             header = area + (GOPheader->getStart() - packet->getStart());
  353.  
  354.             // do we have an open GOP?
  355.             open_GOP = ((header[7] & 0x40) == 0);
  356.         }
  357.  
  358.         // handle B-frame dropping
  359.         if (drop_orphaned_frames && open_GOP && !continuous && !P_Frame_seen)
  360.         {
  361.             Vector *pic_header;
  362.  
  363.             // if this packet has a B-frame, skip it
  364.             if ((pic_header =
  365.                  mpeg2parser->findCode((Vector *) packet,
  366.                                        (uint8_t*)picture_start_code,
  367.                                        6)))
  368.             {
  369.                 int pic_type;
  370.  
  371.                 pic_type =
  372.                     (area[pic_header->getStart() - packet->getStart() + 5] &
  373.                      PICTURE_CODING_MASK) >> 3;
  374.  
  375.                 if (pic_type == PICTURE_CODING_BIDIRECTIONAL)
  376.                 {
  377.                     //printf("Dropping open GOP B-frame on splice\n");
  378.                     okay_to_write = 0;
  379.                     written_pictures--;
  380.                 }
  381.                 if (pic_type == PICTURE_CODING_PREDICTIVE)
  382.                 {
  383.                     //printf("Keeping rest of frames in open GOP splice\n");
  384.                     P_Frame_seen = 1;
  385.                 }
  386.             }
  387.         }
  388.  
  389.         if (okay_to_write)
  390.         {
  391. #ifdef MPEG2_CLIPS_TO_STDERR
  392.             fprintf(stderr, _("\tWriting @ %llu for %d bytes\n"),
  393.                     packet->getStart(), len);
  394. #endif
  395.             memcpy(GOPareaPtr + GOPoffset, area, len);
  396.  
  397.             /* handle making adjustments to GOP header */
  398.             if (has_header)
  399.             {
  400.                 // GOP header is in our current memory area
  401.                 header = GOPareaPtr + GOPoffset +
  402.                             (GOPheader->getStart() - packet->getStart());
  403.  
  404.                 if (!continuous && open_GOP) {
  405.                     // need to set the "broken" flag
  406.  
  407.                     // an editor has been here
  408.                     header[7] |= GOP_FLAG_BROKEN;   
  409.                     // but most decoders don't care
  410.                     if (drop_orphaned_frames)
  411.                         header[7] |= GOP_FLAG_CLOSED;   
  412.                     /*
  413.                        printf("GOP: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
  414.                        header[0],header[1],header[2],header[3],
  415.                        header[4],header[5],header[6],header[7]);
  416.                      */
  417.                 }
  418.  
  419.                 if (adjust_timestamps) {
  420.                     struct sequence_info info;
  421.                     // do it
  422.                     GOP->get_sequence_info(&info);
  423.                     write_timestamp(header,*pictures_written,info.frame_rate);
  424.                 }
  425.             }
  426.  
  427.             GOPoffset += len;
  428.         }
  429.     }
  430.  
  431.     if (GOPoffset > 0)
  432.     {
  433.         // flush to disk
  434.         if (fwrite(GOPareaPtr, sizeof(uint8_t), GOPoffset, file) != GOPoffset)
  435.         {
  436.             printf("%s", _("write failed\n"));
  437.             goto abort;
  438.         }
  439.         written_bytes += GOPoffset;
  440.         *pictures_written += written_pictures;
  441.     }
  442.   abort:
  443.     return written_bytes;
  444. }
  445.  
  446. void write_timestamp(unsigned char * head, uint32_t pictures, int rate) {
  447.     uint32_t seconds, minutes, hours, top, remainder;
  448.  
  449.     //printf("pictures: %u rate: %s ", pictures,frame_str[rate]);
  450.  
  451.     /*
  452.         rate = frames/second
  453.         seconds = frames / rate
  454.         frames = seconds * rate
  455.      */
  456.  
  457.     seconds = pictures * rate_frac[rate].seconds / rate_frac[rate].frames;
  458.     hours = (seconds/60)/60;
  459.     minutes = (seconds/60) % 60;
  460.     seconds = seconds % 60;
  461.     pictures -= seconds * rate_frac[rate].frames / rate_frac[rate].seconds;
  462.  
  463.     //printf("(%d:%d:%d.%d)\n", hours,minutes,seconds,pictures);
  464.  
  465.     head[4]=(head[4]&128)|((hours&0xFF)<<2)|((minutes&0x30)<<4);
  466.     head[5]=((minutes&0x0F)<<4)|(head[5]&0x08)|((seconds&0x38)>>3);
  467.     head[6]=((seconds&0x07)<<5)|((pictures&0x3F)>>1);
  468.     head[7]=((pictures&0x1)<<7)|(head[7]&0x7F);
  469. }
  470.  
  471. /* vi:set ai ts=4 sw=4 expandtab: */
  472.