Пример #1
0
bool mpegmuxer::putpacket(int str, const void *data, int len, pts_t pts, pts_t dts, uint32_t flags)
{
    stream * const s=st[str];
    if (!s)
        return false;
    if (len == 0) {
        // I'm not sure why this happens, but it does. --mr
        fprintf(stderr, "mpegmuxer::putpacket called with zero length, str=%d\n", str);
        return false;
    }
    pts+=ptsoffset;
    dts+=ptsoffset;
    au *newau=new au(data,len,pts,dts,flags);

    if (s->type==streamtype::mpeg2video) {
        uint8_t *audata=(uint8_t*) newau->getdata();

        //     if (0) //
        for (int j=0;j+11<len;) {
            uint8_t *d=audata+j;
            if (d[2]&0xfe)
                j+=3;
            else
                if (((*(u_int32_t*)&d[0])&mbo32(0xffffff00))==mbo32(0x00000100)) {
                    if (d[3]==0x00) // picture header
                    {
                        // vbv delay := 0xffff
                        d[5]|=0x07;
                        d[6]=0xff;
                        d[7]|=0xf8;
                        break;
                    } else if (d[3]==0xb3) // sequence header
                    {
                        d[8]=(VIDEOBITRATE/400) >> 10;
                        d[9]=((VIDEOBITRATE/400) >> 2) & 0xff;
                        d[10]=(((VIDEOBITRATE/400) << 6)&0xc0)|0x20|(((VBVBUFFERSIZE/2)>>5)&0x1f);
                        d[11]=(d[11]&0x07)|((VBVBUFFERSIZE/2)<<3);
                        j+=12;
                    } else if (d[3]==0xb5) // extension
                    {
                        if ((d[4]&0xf0) == 0x10) // sequence extension
                        {
                            // set bitrate_extension and vbv_buffer_size_extension to 0
                            d[6]&=0xe0;
                            d[7]=0x01;
                            d[8]=0;
                            j+=10;
                        } else
                            j+=5;
                    } else
                        j+=4;
                } else
Пример #2
0
void mpgfile::savempg(muxer &mux, int start, int stop, int savedpics, int savepics, logoutput *log)
{
  if (start<0)
    start=0;
  if (start>pictures)
    start=pictures;
  if (stop<0)
    stop=0;
  if (stop>pictures)
    stop=pictures;
  if (start==stop)
    return;
  if (stop<start)
  {
    int x=start;
    start=stop;
    stop=x;
  }

  int seekpic=idx.indexnr(start);
  int framerate = mpgfile::frameratescr[idx[seekpic].getframerate()];
  bool fixedstart=true;

  if (mux.isempty())
  {
    fixedstart=false;
    mux.unsetempty();
    pts_t startpts = framerate / 300;
    for (int i=0;i<MAXAVSTREAMS;++i)
      mux.setpts(i,startpts);
  }

  pts_t videostartpts=idx[seekpic].getpts();
  pts_t videostoppts=idx[idx.indexnr(stop)].getpts();
  pts_t videooffset=videostartpts-mux.getpts(VIDEOSTREAM);
  pts_t audiopts[MAXAUDIOSTREAMS];
  pts_t audiostartpts[MAXAUDIOSTREAMS];
  pts_t audiooffset[MAXAUDIOSTREAMS];
  for(int a=0;a<MAXAUDIOSTREAMS;++a)
  {
    audiooffset[a]=videooffset;
    audiostartpts[a]=audiopts[a]=videostartpts;
  }
  pts_t shift=0;

  {
    dvbcut_off_t start_pos = idx[idx.indexnr(start)].getpos().fileposition();
    dvbcut_off_t stop_pos = idx[idx.indexnr(stop)].getpos().fileposition();
    dvbcut_off_t bytes = stop_pos - start_pos;
    pts_t delta_pts = (pts_t)(stop - start) * framerate / 300;
    double mux_rate = (double)bytes * 9e4 / (double)delta_pts;
    if (log) {
      //: Placeholder will be replaced with floating point number
      log->printinfo(QCoreApplication::translate("mpgfile", "Estimated mux rate: %1 MB/s").arg(mux_rate * 1e-6, 0, 'f', 2));
    }
  }

  while (seekpic>0 && idx[seekpic].getpts()>=videostartpts-180000)
    --seekpic;

  dvbcut_off_t tpos;
  {
    int stoppic=idx.indexnr(start);
    while (stoppic<pictures &&
           (idx[stoppic].getpts()<videostartpts+180000 || !idx[stoppic].getseqheader()))
      ++stoppic;
    tpos=idx[stoppic].getpos().packetposition();
  }

  streamhandle sh(idx[seekpic].getpos().packetposition());
  streamdata *vsd=sh.newstream(VIDEOSTREAM,s[VIDEOSTREAM].type,istransportstream());
  for (int a=0;a<MAXAUDIOSTREAMS;++a)
    if (mux.streampresent(audiostream(a)))
      sh.newstream(audiostream(a),s[audiostream(a)].type,istransportstream());

  while (sh.fileposition<tpos)
    if (streamreader(sh)<0)
      break;

  for (int a=0;a<MAXAUDIOSTREAMS;++a)
    if (streamdata *sd=sh.stream[audiostream(a)])
    {
      pts_t tpts=videostartpts-mux.getpts(VIDEOSTREAM)+mux.getpts(audiostream(a));
      sd->audio_addpts();
      uint32_t startbufferpos=sd->ptsbufferpos(tpts);
      if (startbufferpos>sd->getoffset())
        sd->discard(startbufferpos-sd->getoffset());
      sd->audio_addpts(0,true);
      startbufferpos=sd->closestptsbufferpos(tpts);
      if (startbufferpos>sd->getoffset())
        sd->discard(startbufferpos-sd->getoffset());

      pts_t apts=sd->itemlist().front().headerpts(tpts);
      audiostartpts[a]=apts;
      if (apts>=0)
      {
        if (fixedstart)
          audiooffset[a]=videooffset-tpts+apts;
        else if (tpts-apts>shift)
          shift=tpts-apts;
      }

    }

  if (!fixedstart)
  {
    videooffset-=shift;
    for(int a=0;a<MAXAUDIOSTREAMS;++a)
      audiooffset[a]=videooffset;
  }

  pts_t audiostoppts[MAXAUDIOSTREAMS];
  for(int a=0;a<MAXAUDIOSTREAMS;++a)
    audiostoppts[a]=videostoppts-videooffset+audiooffset[a];

  int firstseqhdr=nextseqheader(start);
  {
    filepos_t copystart=idx[idx.indexnr(firstseqhdr)].getpos();
    vsd->discard(vsd->fileposbufferpos(copystart)-vsd->getoffset());
  }
  bool isfirstpic=true, isfirstseq=true;
  int firstseqnr=idx[idx.indexnr(firstseqhdr)].getsequencenumber();

  if (firstseqhdr>start)
  {
    recodevideo(mux,start,firstseqhdr,videooffset,savedpics,savepics,log);
    savedpics+=firstseqhdr-start;
  }

  int copystop=stop; // first picture not to write to stream
  while (copystop<pictures && idx[idx.indexnr(copystop)].isbframe())
    ++copystop;
  copystop=idx.indexnr(copystop);

  int streampic=idx.indexnr(firstseqhdr);

  while (!log || !log->cancelled())
  {
    int packetsread;
    for (packetsread=0;packetsread<20;++packetsread)
      if (streamreader(sh)<=0)
        break;
    if (packetsread==0)
      break;

    // copy video
    if (vsd)
      for(;;)
      {
        if (streampic>=copystop)
        {
          vsd=0;
          sh.delstream(VIDEOSTREAM);
          break;
        }

        uint32_t picsize=vsd->fileposbufferpos(idx[streampic+1].getpos())-vsd->getoffset();
        if (picsize>=vsd->inbytes())
          break;

        if (!isfirstpic && idx[streampic].getseqheader())
          isfirstseq=false;
        isfirstpic=false;

        int seqoff=0;
        if (!isfirstseq || idx[streampic].getsequencenumber()>=firstseqnr)
        {
          if (isfirstseq && firstseqnr>0) // need to subtract offset from picture sequence number
          {
            uint8_t *d=(uint8_t*) vsd->getdata();

            for (unsigned int j=0;j+5<picsize;)
            {
              if (d[2]&0xfe)
                j+=3;
              else
                if (*(u_int32_t*)&d[j]==mbo32(0x00000100))
                {
                  int seqpic=(d[j+4]<<2)|((d[j+5]>>6)&0x03);
                  seqpic-=firstseqnr;
                  d[j+4]=seqpic>>2;
                  d[j+5]=(d[j+5]&0x3f)|((seqpic<<6)&0xc0);
                  break;
                }
                else
                  ++j;
            }
            seqoff=firstseqnr;
          }
          pts_t vidpts=idx[streampic].getpts()-videooffset;
          pts_t viddts=vidpts;
          if (!idx[streampic].isbframe())
          {
            viddts=mux.getdts(VIDEOSTREAM);
            mux.setdts(VIDEOSTREAM,vidpts);
          }
          if (idx[streampic].getseqheader())
          {
            int tcpic=streampic;
            while (tcpic < copystop && idx[tcpic].getsequencenumber() != seqoff)
              ++tcpic;
            pts_t tcpts=idx[tcpic].getpts()-videooffset;
            fixtimecode((uint8_t*)vsd->getdata(),picsize,tcpts);
          }
          if (!mux.putpacket(VIDEOSTREAM,vsd->getdata(),picsize,vidpts,viddts,
                             idx[streampic].isiframe() ? MUXER_FLAG_KEY:0  ))
            {
              if (log) {
                //: Placeholder will be replaced with streampic number
                log->printwarning(QCoreApplication::translate("mpgfile", "putpacket(streampic=%1) returned false").arg(streampic));
              } else {
                fprintf(stderr,"WARN: putpacket(streampic=%d) returned false\n",streampic);
              }
            }
        }
Пример #3
0
mpegmuxer::mpegmuxer(uint32_t audiostreammask, mpgfile &mpg, const char *filename, bool dvd,
                     int packsize_bytes, int muxrate_bitsps) :
    fd(-1), st(), muxrate(muxrate_bitsps/400), packsize(packsize_bytes), ptsoffset(0), aucounter(0),
    systemhdr(0), systemhdrlen(0), pespacket_setlength(true),scr(0)
{
    if (packsize<MINPACKSIZE)
        packsize=0;
    scrpack=int(27.e6/double(muxrate*50)*packsize+0.9999);

    st[VIDEOSTREAM]=new stream(streamtype::mpeg2video,0xe0,232<<10,232<<10,true);
    strpres[VIDEOSTREAM]=true;

    int audiobuffersize=dvd?(4<<10):(48<<10);
    for (int i=0;i<mpg.getaudiostreams();++i)
        if (audiostreammask & (1u<<i)) {
            streamtype::type t = mpg.getstreamtype(audiostream(i));
            if (t==streamtype::ac3audio)
                st[audiostream(i)]=new stream(t, 0x180+i,
                                              audiobuffersize,58<<10,true);
            /* not supported yet:
      else if (t==streamtype::dtsaudio)
        st[audiostream(i)]=new stream(t, 0x188+i,
                                      audiobuffersize,58<<10,true);
      */
            else
                st[audiostream(i)]=new stream(t, 0xc0+i,
                                              audiobuffersize,audiobuffersize,false);
            strpres[audiostream(i)]=true;
        }

    systemhdrlen=dvd ? 2034 : 24; // include DVD navigation packets if dvd set
    systemhdr = (void*) calloc(1, systemhdrlen);
    bzero(systemhdr,systemhdrlen);

    {
        systemhdr_s *value = (systemhdr_s*) systemhdr;
        *value = {
                mbo32(0x000001bb),mbo16(18),
                //1,muxrate,1,mpg.getaudiostreams(),0,0,
                htom32(0x80000100 | ((muxrate&0x3fffff)<<9) | (mpg.getaudiostreams()<<2)),
                //1,1,1,1,
                0xe1,
                //0,0x7f,
                0x7f,
                0xb9,mbo16(0xe000|232),0xb8,mbo16(0xc000|32),
                0xbd,mbo16(0xe000|58),0xbf,mbo16(0xe000|2)
        };
    }
    if (dvd) { // dvd nav packets
        *(uint32_t*)((char*)systemhdr+24)=mbo32(0x000001bf);
        *(uint16_t*)((char*)systemhdr+28)=mbo16(980);
        *(uint32_t*)((char*)systemhdr+1010)=mbo32(0x000001bf);
        *(uint16_t*)((char*)systemhdr+1014)=mbo16(1018);
    }

    // total size of all buffers: 232kB video + 4kB per mpeg audio stream
    double allbuffers(double((232<<10)+mpg.getaudiostreams()*(4<<10)));
    allbuffers*=1.05; // 5% assumed muxing overhead
    ptsoffset=pts_t(90000.*(allbuffers/50./muxrate))+90;

    if (!strncmp(filename, "pipe:", 5))
        fd = atoi(filename+5);
    else
        fd=::open(filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666);
}