/**
        \fn refill
*/
bool ADM_audioStreamBuffered::refill(void)
{
        // Shrink buffer...
        if(limit>ADM_AUDIOSTREAM_BUFFER_SIZE && start> 10*1024)
        {
            //printf("[Shrink]\n");
            memmove(buffer.at(0), buffer.at(start),limit-start);
            limit-=start;
            start=0;
        }
        uint64_t newDts;
        uint32_t size;
        ADM_assert(limit<(2*ADM_AUDIOSTREAM_BUFFER_SIZE-16));
        uint32_t toRead=2*ADM_AUDIOSTREAM_BUFFER_SIZE-limit-16;
        if(true!=access->getPacket(buffer.at(limit), &size, toRead,&newDts))
                return false;
        // We introduce a small error as there might be some bytes left in the buffer
        // By construction, the error should be minimal
        if(newDts!=ADM_AUDIO_NO_DTS)
        {
            if( abs(newDts-lastDts)>ADM_MAX_SKEW)
            {
                printf("[AudioStream] Warning skew in dts =%"PRId64", \n",(int64_t)newDts-(uint64_t)lastDts);
                printf("[AudioStream] Warning skew lastDts=%s \n",ADM_us2plain(lastDts));
                printf("[AudioStream] Warning skew newDts=%s  \n",ADM_us2plain(newDts));
                setDts(newDts);
            }
            // If we have a DTS and the buffer is empty, set the dts inconditionnaly
            if(!start) setDts(newDts); // Fixme allow a bit of error, not accumulating
        }
        limit+=size;
        ADM_assert(limit<ADM_AUDIOSTREAM_BUFFER_SIZE*2);
        return true;
}
/**
    \fn shiftAudioVideoBy
    \brief shift audio and video so that they start close to zero
*/
bool asfHeader::shiftAudioVideoBy(uint64_t s)
{
    int n=_index.size();
    ADM_info("Shifting by %s\n",ADM_us2plain(s));
    for(int i=0;i<n;i++)
    {
        if(_index[i].pts!=ADM_NO_PTS)
        {
            if(_index[i].pts<s)
            {
                ADM_error("Shifting too big for frame %d PTS: %s\n",i,ADM_us2plain(_index[i].pts));
            }else
                _index[i].pts-=s;
        }
        _index[i].dts=ADM_NO_PTS;
/*
        if(_index[i].dts!=ADM_NO_PTS)
        {
            if(_index[i].dts<s)
            {
                ADM_error("Shifting too big for frame %d DTS: %s\n",i,ADM_us2plain(_index[i].dts));
                _index[i].dts=ADM_NO_PTS;
            }else
                _index[i].dts-=s;
        }
*/
    }
    _shiftUs=s;
    return true;
}
Example #3
0
/**
 *      \fn getConfiguration
 * 
 */
const char   *AVDM_Fade::getConfiguration(void)
{
 static char conf[256];
    std::string start=std::string(ADM_us2plain(param.startFade*1000LL));
    std::string end=std::string(ADM_us2plain(param.endFade*1000LL));
    snprintf(conf,255," Fade : Start %s End %s",start.c_str(),end.c_str());
    return conf;
}
/**
    \fn checkCutsAreOnIntra
    \brief In copy mode, if the cuts are not on intra we will run into trouble :
            * We include skipped ref frames: we will have DTS going back error
            * We skip them, we have borked video at cut points due to missing ref framesz
    \return true if everything ok
*/
bool ADM_Composer::checkCutsAreOnIntra(void)
{
    bool fail=false;
    int nbSeg=_segments.getNbSegments();

    ADMCompressedImage img;
    uint8_t *buffer=new uint8_t[1920*1080*3];
    img.data=buffer;
    ADM_info("Checking cuts start on keyframe..\n");
    for(int i=0; i<nbSeg; i++)
    {
        _SEGMENT *seg=_segments.getSegment(i);
        _VIDEOS *vid=_segments.getRefVideo(seg->_reference);
        vidHeader *demuxer=vid->_aviheader;

        if(false==switchToSegment(i,true))
        {
            fail=true;
            break;
        }
        if(false==demuxer->getFrame (vid->lastSentFrame,&img))
        {
            ADM_info("Cannot get 1st frame of segment %d\n",i);
            fail=true;
            break;
        }
        if(!img.flags & AVI_KEY_FRAME)
        {
            ADM_warning("Segment %d does not start on a keyframe (%s)\n",i,ADM_us2plain(img.demuxerPts));
            fail=true;
            break;
        }
        // After a seg switch we are at the keyframe before or equal to where we want to go
        // if the dts do not match, it means we went back too much
        // When re-encoding, it's not a problem, it is when copying.
        ADM_info("seg:%d refDTS=%"PRIu64"\n",seg->_reference,seg->_refStartDts);
        ADM_info("seg:%d imgDTS=%"PRIu64"\n",seg->_reference,img.demuxerDts);
        if(!seg->_refStartDts && !seg->_reference)
        {
            ADM_info("Ignoring first seg (unreliable DTS)\n");

        } else if(img.demuxerDts!=ADM_NO_PTS && seg->_refStartDts!=ADM_NO_PTS &&
                  img.demuxerDts!=seg->_refStartDts)
        {
            ADM_warning("Segment %d does not start on a known DTS (%s)\n",i,ADM_us2plain(img.demuxerPts));
            ADM_warning("expected (%s)\n",ADM_us2plain(seg->_refStartDts));
            fail=true;
            break;
        }
        ADM_info("Segment %d ok\n",i);
    }
    delete [] buffer;
    buffer=NULL;
    if(fail) return false;
    return true;
}
Example #5
0
void ADM_EditorSegment::dumpSegmentsInternal(ListOfSegments &l)
{
    int n=l.size();
    for(int i=0;i<n;i++)
    {
        _SEGMENT s=l.at(i);

        printf("Segment :%d/%d\n",i,n);
        printf("\tReference    :%"PRIu32"    %s\n",s._reference,ADM_us2plain(s._reference));
        printf("\tstartLinear  :%08"PRIu64" %s\n",s._startTimeUs,ADM_us2plain(s._startTimeUs));
        printf("\tduration     :%08"PRIu64" %s\n",s._durationUs,ADM_us2plain(s._durationUs));
        printf("\trefStartPts  :%08"PRIu64" %s\n",s._refStartTimeUs,ADM_us2plain(s._refStartTimeUs));
        printf("\trefStartDts  :%08"PRIu64" %s\n",s._refStartDts,ADM_us2plain(s._refStartDts));
    }
}
/**
 *      \fn switchToNextAudioSegment
 *
 */
bool ADM_edAudioTrackFromVideo::switchToNextAudioSegment(void)
{
        // Try to switch segment
        if(_audioSeg+1>=parent->_segments.getNbSegments()) return false;

        ADM_warning("Switching to segment %"PRIu32"\n",_audioSeg+1);
        _audioSeg++;
        _SEGMENT *seg=parent->_segments.getSegment(_audioSeg);
        ADM_audioStreamTrack *trk=getTrackAtVideoNumber(seg->_reference);
        //
        ADM_Audiocodec *codec=NULL;
        if(trk)
            if(trk->codec)
                codec=trk->codec;
        if(codec)
        {
            codec->resetAfterSeek();
        }
        // Go to beginning of the stream
        if(false==trk->stream->goToTime(seg->_refStartTimeUs))
          {
            ADM_warning("Fail to seek audio to %"PRIu64"ms\n",seg->_refStartTimeUs/1000);
            return false;
          }
        ADM_info("Switched ok to audio segment %"PRIu32", with a ref time=%s\n",
            _audioSeg,ADM_us2plain(seg->_refStartTimeUs));
        return true;

}
/**
        \fn getPacket
*/
uint8_t ADM_audioStreamConstantChunk::getPacket(uint8_t *buffer,uint32_t *size, uint32_t sizeMax,uint32_t *nbSample,uint64_t *dts)
{
    *size=0;
    *nbSample=0;
    if(sizeMax>=chunkSize)
    {
        uint32_t mSize;
        uint64_t mDts;
        if(!access->getPacket(buffer,&mSize,sizeMax,&mDts)) 
        {
                ADM_warning("Cant get packet\n");
                return 0;
        }
        ADM_info("Got packet : chunk=%d size=%d dts=%s\n",chunkSize,mSize,ADM_us2plain(mDts));
        if(!*size)
            *dts=mDts;

        *size+=mSize;
        *nbSample+=samplesPerChunk;
        if(mSize!=chunkSize)
        {
            ADM_warning("Expected chunk of size =%d, got %d\n",chunkSize,mSize);
        }

        buffer+=mSize;
        sizeMax-=mSize;
     }
     if(!*size) return 0;
     return 1;
}
Example #8
0
/**
    \fn dumpRefVideos
    \brief Dump the refVideo content
*/
void ADM_EditorSegment::dumpRefVideos(void)
{

    int n=videos.size();
    printf("We have %d reference videos\n",n);
    for(int i=0;i<n;i++)
    {
        _VIDEOS *s=getRefVideo(i);

        printf("Videos :%d/%d\n",i,n);
        printf("\tfirstFramePts      :%08"PRIu64" %s\n",s->firstFramePts,ADM_us2plain(s->firstFramePts));
        printf("\ttimeIncrementInUs  :%08"PRIu64" %s\n",s->timeIncrementInUs,ADM_us2plain(s->timeIncrementInUs));
        printf("\tnb frames    :%04"PRIu32"\n",s->_nb_video_frames);
    }

}
uint8_t  MP4Header::getFrame(uint32_t framenum,ADMCompressedImage *img)
{
    aprintf("[MP4] frame %d requested (nbFrame=%d)\n",framenum,VDEO.nbIndex);
    if(framenum>=VDEO.nbIndex)
    {
      return 0;
    }

MP4Index *idx=&(VDEO.index[framenum]);

    uint64_t offset=idx->offset; //+_mdatOffset;


    fseeko(_fd,offset,SEEK_SET);
    fread(img->data, idx->size, 1, _fd);
    img->dataLength=idx->size;
	img->flags = idx->intra;

    img->demuxerDts=idx->dts;
    img->demuxerPts=idx->pts;
    aprintf("[MP4] Pts=%s\n",ADM_us2plain(idx->pts));
    /*
    if(img->demuxerPts==ADM_COMPRESSED_NO_PTS)
        img->demuxerPts=img->demuxerDts;
    */
    return 1;
}
/**
        \fn fillAudio
        \brief Put audio datas until targetDts is reached
*/
bool muxerAvi::fillAudio(uint64_t targetDts)
{
// Now send audio until they all have DTS > lastVideoDts+increment
            for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
            {
                ADM_audioStream*a=aStreams[audioIndex];
                uint32_t fq=a->getInfo()->frequency;
                int nb=0;
                audioClock *clk=clocks[audioIndex];
                aviAudioPacket *aPacket=audioPackets+audioIndex;
                if(true==aPacket->eos) return true;
                while(1)
                {
                    if(false==aPacket->present)
                    {
                        if(!a->getPacket(aPacket->buffer,
                                         &(aPacket->sizeInBytes),
                                         AUDIO_BUFFER_SIZE,
                                         &(aPacket->nbSamples),
                                         &(aPacket->dts)))
                        {
                                ADM_warning("Cannot get audio packet for stream %d\n",audioIndex);
                                aPacket->eos=true;
                                break;
                        }
                            if(aPacket->dts!=ADM_NO_PTS) 
                            {
                                aPacket->dts+=audioDelay;
                                aPacket->dts-=firstPacketOffset;
                            }
                            aprintf("[Audio] Packet size %"PRIu32" sample:%"PRIu32" dts:%"PRIu64" target :%"PRIu64"\n",
                                            aPacket->sizeInBytes,aPacket->nbSamples,aPacket->dts,targetDts);
                            if(aPacket->dts!=ADM_NO_PTS)
                                if( abs(aPacket->dts-clk->getTimeUs())>32000)
                                {
                                    ADM_warning("[AviMuxer] Audio skew!\n");
                                    clk->setTimeUs(aPacket->dts);
#warning FIXME add padding
                                }
                            aPacket->present=true;
                    }
                    // We now have a packet stored
                    aprintf("Audio packet dts =%s\n",ADM_us2plain(aPacket->dts));
                    if(aPacket->dts!=ADM_NO_PTS)
                        if(aPacket->dts>targetDts) 
                        {
                            aprintf("In the future..\n");
                            break; // this one is in the future
                        }
                    nb=writter.saveAudioFrame(audioIndex,aPacket->sizeInBytes,aPacket->buffer) ;
                    encoding->pushAudioFrame(aPacket->sizeInBytes);
                    aprintf("writting audio packet\n");
                    clk->advanceBySample(aPacket->nbSamples);
                    aPacket->present=false;
                    //printf("%u vs %u\n",audioDts/1000,(lastVideoDts+videoIncrement)/1000);
                }
            }

            return true;
}
Example #11
0
/**
    \fn updateRefVideo
    \brief Update start time
*/
bool        ADM_EditorSegment::updateRefVideo(void)
{
    int n=videos.size();
    ADM_assert(n);
    _VIDEOS *ref=getRefVideo(n-1);
    vidHeader *demuxer=ref->_aviheader;
    uint64_t pts,dts;

        demuxer->getPtsDts(0,&pts,&dts);
        if(pts!=ADM_NO_PTS && pts >0)
        {
            ADM_warning("Updating firstFramePTS, The first frame has a PTS >0, adjusting to %"PRIu64" ms\n",pts/1000);
            ref->firstFramePts=pts;
        }else
        {
            ADM_info("First PTS is %s\n",ADM_us2plain(pts));
        }

    updateStartTime();
    //
    n=segments.size();
    if(n)
    {
    _SEGMENT *seg=getSegment(n-1);
    uint64_t dur=ref->_aviheader->getVideoDuration();
    printf("Current duration %"PRIu64" ms real one %"PRIu64" ms\n",dur/1000,seg->_durationUs/1000);
    }

    return true;
}
Example #12
0
void       ADM_EditorSegment::dumpSegment(int i)
{
    int n=segments.size();
    if(i>=n)
    {
        ADM_error("Segment %d too big (%d)\n",i,(int)n);
        return ;
    }
        _SEGMENT *s=getSegment(i);

        printf("Segment :%d/%d\n",i,n);
        printf("\tReference    :%"PRIu32"    %s\n",s->_reference,ADM_us2plain(s->_reference));
        printf("\tstartLinear  :%08"PRIu64" %s\n",s->_startTimeUs,ADM_us2plain(s->_startTimeUs));
        printf("\tduration     :%08"PRIu64" %s\n",s->_durationUs,ADM_us2plain(s->_durationUs));
        printf("\trefStartPts  :%08"PRIu64" %s\n",s->_refStartTimeUs,ADM_us2plain(s->_refStartTimeUs));
        printf("\trefStartDts  :%08"PRIu64" %s\n",s->_refStartDts,ADM_us2plain(s->_refStartDts));
}
/**
    \fn getNextFrame
    \brief 

*/
bool vdpauVideoFilterDeint::getNextFrame(uint32_t *fn,ADMImage *image)
{
bool r=true;
    if(eof)
    {
        ADM_warning("[VdpauDeint] End of stream\n");
        return false;
    }
#define FAIL {r=false;goto endit;}
     if(passThrough) return previousFilter->getNextFrame(fn,image);
    // top field has already been sent, grab bottom field
    if((secondField)&&(configuration.deintMode==ADM_KEEP_BOTH))
        {
            secondField=false;
            *fn=nextFrame*2+1;
            if(false==getResult(image)) return false;
            if(ADM_NO_PTS==nextPts) image->Pts=nextPts;
                else image->Pts=nextPts-info.frameIncrement;
            aprintf("2ndField : Pts=%s\n",ADM_us2plain(image->Pts));
            return true;
        }
     // shift frames;... free slot[0]
    rotateSlots();

    // our first frame, we need to preload one frame
    if(!nextFrame)
    {
            aprintf("This is our first image, filling slot 1\n");
            ADMImage *prev= vidCache->getImageAs(ADM_HW_VDPAU,0);
            if(false==fillSlot(1,prev))
            {
                    vidCache->unlockAll();
                    return false;
            }
            if(false==fillSlot(0,prev))
            {
                    vidCache->unlockAll();
                    return false;
            }
            
    }
    // regular image, in fact we get the next image here
    ADMImage *next= vidCache->getImageAs(ADM_HW_VDPAU,nextFrame+1);
    if(next)
    {
            if(false==fillSlot(2,next))
            {
                vidCache->unlockAll();
                FAIL
            }
    }
Example #14
0
/**
 * \fn copyToClipBoard
 * \Brief copy the section between startTime and endTime to clipboard
 * @param startTime
 * @param endTime
 * @return 
 */
bool        ADM_EditorSegment::copyToClipBoard(uint64_t startTime, uint64_t endTime)
{
    ADM_info("Copy to clipboard from %s",ADM_us2plain(startTime));
    ADM_info("to %s\n",ADM_us2plain(endTime));
    uint32_t startSeg,endSeg;
    uint64_t startSegTime,endSegTime;
    convertLinearTimeToSeg(  startTime, &startSeg,&startSegTime);
    convertLinearTimeToSeg(  endTime, &endSeg,&endSegTime);
    dump();
    clipboard.clear();
    for(int seg=startSeg;seg<=endSeg;seg++)
    {
        _SEGMENT s=segments[seg];
        aprintf("Adding segment %d to clipboard\n",seg);
        if(s._startTimeUs<=startTime && (s._startTimeUs+s._durationUs)>startTime)
        {
            // need to refine 1st seg

            uint64_t offset=startTime-s._startTimeUs;
            s._refStartTimeUs+=offset;
            s._durationUs-=offset;         // take into account the part we chopped
            aprintf("Marker A is here offset=%d\n",(int)offset);
        }
        if(s._startTimeUs<=endTime && (s._startTimeUs+s._durationUs)>endTime)
        {
            
            // need to refine last seg            
            uint64_t offset=endTime-s._startTimeUs;
            s._durationUs=offset;
            aprintf("Marker B is here offset=%d\n",(int)offset);
        }
        // TODO refine timing for 1st/last/duration/...
        clipboard.push_back(s);        
    }
    dumpClipBoard();
    return false;
}
Example #15
0
/**
 * \fn pasteFromClipBoard
 * \brief instert clipboard at currentTime position
 * @param currentTime
 * @return 
 */
bool        ADM_EditorSegment::pasteFromClipBoard(uint64_t currentTime)
{
    if(clipboardEmpty())
    {
        ADM_info("The clipboard is empty, nothing to do\n");
        return true;
    }
    ADM_info("Pasting from clipboard to %s\n",ADM_us2plain(currentTime));
    uint32_t startSeg;
    uint64_t startSegTime;
    convertLinearTimeToSeg(  currentTime, &startSeg,&startSegTime);    
    ListOfSegments tmp=segments;
    ListOfSegments newSegs;
    int n=segments.size();
    for(int i=0;i<n;i++)
    {
        _SEGMENT s=segments[i];
        if(i==startSeg)
        {
            // insert clipboard
            // Do we need to split it ?
            if(currentTime==s._startTimeUs)
            {
                // nope
                for(int j=0;j<clipboard.size();j++) newSegs.push_back(clipboard[j]);
            }else
            {
                 _SEGMENT pre=s,post=s;
                 uint64_t offset=currentTime-s._startTimeUs;
                 pre._durationUs=offset;
                 post._refStartTimeUs+=offset;
                 post._durationUs-=offset;
                 newSegs.push_back(pre);
                 for(int j=0;j<clipboard.size();j++) newSegs.push_back(clipboard[j]);
                 newSegs.push_back(post);
                 continue;
            }
                    
        }
        newSegs.push_back(s);
    }
    segments=newSegs;
    // If a video doesn't start at zero and we paste to its first frame,
    // we end up with an empty segment at the beginning. Remove it.
    removeEmptySegments();
    updateStartTime();
    dump();
    return true;
}
/**
 * \fn prefill
 *  \brief load first audio & video packets to get the 1st packet offset
 *        Needed to avoid adding fillers for both audio & video at the beginning
 * @return 
 */
bool muxerAvi::prefill(ADMBitstream *in)
{
    
    uint64_t dts=0;
    if(false==vStream->getPacket(in)) 
    {
        ADM_error("Cannot get first video frame\n");
        return false;
    }
    dts=in->dts;
    for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
    {
                ADM_audioStream*a=aStreams[audioIndex];
                audioClock *clk=clocks[audioIndex];
                aviAudioPacket *aPacket=audioPackets+audioIndex;
                if(!a->getPacket(aPacket->buffer,
                                 &(aPacket->sizeInBytes),
                                 AUDIO_BUFFER_SIZE,
                                 &(aPacket->nbSamples),
                                 &(aPacket->dts)))
                {
                        ADM_warning("Cannot get audio packet for stream %d\n",audioIndex);
                        aPacket->eos=true;
                        aPacket->present=false;
                        continue;
                }
                aPacket->present=true;
                if(aPacket->dts!=ADM_NO_PTS) 
                {
                        aPacket->dts+=audioDelay;
                }
                if(dts==ADM_NO_PTS) dts=aPacket->dts;
                if(aPacket->dts!=ADM_NO_PTS && dts!=ADM_NO_PTS)
                        if(aPacket->dts<dts) dts=aPacket->dts;
    }
    ADM_info("Min 1st packet time :%s\n",ADM_us2plain(dts));
    if(dts!=ADM_NO_PTS) firstPacketOffset=dts;
    
    rescaleVideo(in,firstPacketOffset);
    for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
    {
         aviAudioPacket *aPacket=audioPackets+audioIndex;
         if(!aPacket->present) continue;
         if(aPacket->dts!=ADM_NO_PTS) aPacket->dts-=firstPacketOffset;
    }
    return true;
}
/**
    \fn refillPacketBuffer
*/
bool             ADM_edAudioTrackExternal::refillPacketBuffer(void)
{
   packetBufferSize=0; 
   uint64_t dts;
 
    if(!internalAudioStream->getPacket(packetBuffer,&packetBufferSize,ADM_EDITOR_PACKET_BUFFER_SIZE,
                        &packetBufferSamples,&dts))
    {           
             return false;
    }
    //
    // Ok we have a packet, rescale audio
    //if(dts==ADM_NO_PTS) packetBufferDts=ADM_NO_PTS;
    packetBufferDts=dts; // Could have a small error here..
    vprintf("Refilling buffer dts=%s\n",ADM_us2plain(packetBufferDts));
    return true;
}
/**
    \fn     initUI
    \brief  initialize the progress bar
*/
bool     ADM_muxer::initUI(const char *title)
{
        bool useTray = false;

        if (!prefs->get(FEATURES_USE_SYSTRAY, &useTray))
            useTray = false;

        videoIncrement=vStream->getFrameIncrement();  // Video increment in AVI-Tick
        videoDuration=vStream->getVideoDuration();
        ADM_info("Muxer, creating UI, video duration is %s\n",ADM_us2plain(videoDuration));
        encoding=createEncoding(videoDuration,useTray);
        // Set video stream etc...
        encoding->setVideoCodec(fourCC::tostring(vStream->getFCC()));
        if(!nbAStreams) encoding->setAudioCodec("None");
                else    encoding->setAudioCodec(getStrFromAudioCodec(aStreams[0]->getInfo()->encoding));
        return true;
}
Example #19
0
/**
 * \fn pasteFromClipBoard
 * \brief instert clipboard at currentTime position
 * @param currentTime
 * @return 
 */
bool        ADM_EditorSegment::pasteFromClipBoard(uint64_t currentTime)
{
    ADM_info("Pasting from clipboard to %s\n",ADM_us2plain(currentTime));
    uint32_t startSeg;
    uint64_t startSegTime;
    convertLinearTimeToSeg(  currentTime, &startSeg,&startSegTime);    
    ListOfSegments newSegs;
    int n=segments.size();
    for(int i=0;i<n;i++)
    {
        _SEGMENT s=segments[i];
        if(i==startSeg)
        {
            // insert clipboard
            // Do we need to split it ?
            if(currentTime==s._startTimeUs)
            {
                // nope
                for(int j=0;j<clipboard.size();j++) newSegs.push_back(clipboard[j]);
            }else
            {
                 _SEGMENT pre=s,post=s;
                 uint64_t offset=currentTime-s._startTimeUs;
                 pre._durationUs=offset;
                 post._refStartTimeUs+=offset;
                 post._durationUs-=offset;
                 newSegs.push_back(pre);
                 for(int j=0;j<clipboard.size();j++) newSegs.push_back(clipboard[j]);
                 newSegs.push_back(post);
                 continue;
            }
                    
        }
        newSegs.push_back(s);
    }
    segments=newSegs;
    updateStartTime();
    return true;
}
/**
    \fn loadAndToggleAudioSlot
*/
bool muxerMp4v2::loadAndToggleAudioSlot(int index)
{
        ADM_audioStream                     *a=aStreams[index];
        mp4v2AudioPacket                    *pkt=&(audioPackets[index]);
        mp4v2AudioPacket::mp4v2AudioBlock   *blk=&(pkt->blocks[pkt->nextWrite]);
        if(!a->getPacket(blk->buffer,
                         &(blk->sizeInBytes),
                         AUDIO_BUFFER_SIZE,
                         &(blk->nbSamples),
                         &(blk->dts)))
        {
                ADM_warning("Cannot get audio packet for stream %d\n",index);
                pkt->eos=true;
                return false;
        }
        if(blk->dts!=ADM_NO_PTS)
            blk->dts+=audioDelay;
        blk->present=true;
        pkt->nextWrite=!pkt->nextWrite;
        aprintf("Read audio block, size=%d bytes, dts=%s\n",blk->sizeInBytes,ADM_us2plain(blk->dts));
        return true;
}
/**
    \fn ADM_audioStreamConstantChunk
    \brief constructor
*/
ADM_audioStreamConstantChunk::ADM_audioStreamConstantChunk(WAVHeader *header,ADM_audioAccess *access) 
    : ADM_audioStream(header,access)
{
    //
    chunkSize=header->blockalign;
    if(!chunkSize)
    {
        ADM_warning("[ADM_audioStreamConstantChunk] Blockalign is null expect problems\n");
        chunkSize=8192; // dummy value
    }
    ADM_info("[ADM_audioStreamConstantChunk] Chunk size %" PRIu32"\n",chunkSize);
    ADM_info("[ADM_audioStreamConstantChunk] Byterate   %" PRIu32"\n",header->byterate);
    // Compute sample per chunk from wavHeader...
    float f;
    f=chunkSize;
    f/=header->byterate; // F is in seconds
    f*=header->frequency; // in sample
    samplesPerChunk=(uint32_t)f;
    ADM_info("[ADM_audioStreamConstantChunk] About %" PRIu32" samples per chunk\n",samplesPerChunk);
    //samplesPerChunk=16;
    // If hinted..., compute the duration ourselves
    if(access->isCBR()==true && access->canSeekOffset()==true)
    {
        // We can compute the duration from the length
        float size=access->getLength();
              size/=header->byterate; // Result is in second
              size*=1000;
              size*=1000; // s->us
              durationInUs=(uint64_t)size;
              ADM_info("Computed duration %s\n",ADM_us2plain(durationInUs));
              return;
    }
// Time based
    durationInUs=access->getDurationInUs();
    

}
Example #22
0
/**
    \fn intraTimeToFrame
    \brief Return the frame whosePTS==seektime, assert if does not exist
*/
uint32_t    ADM_EditorSegment::intraTimeToFrame(uint32_t refVideo,uint64_t seekTime)
{
        uint32_t frame;
        uint32_t flags;
        _VIDEOS *v=getRefVideo(refVideo);
        ADM_assert(v);
        if(false==TimeToFrame(v,seekTime,&frame,&flags))
        {
            ADM_error("Cannot find frame with time %"PRIu64"ms\n",seekTime/1000);
            ADM_assert(0);
        }
        uint32_t next;
        v->_aviheader->getFlags(frame+1,&next);
        if(!((next | flags) & AVI_KEY_FRAME)) // The 2nd field might be keyframe
        {
                ADM_warning("Seeking to a non keyframe (time=%s), flags=%x, flagsNext=%x\n",ADM_us2plain(seekTime),flags,next);
                ADM_warning("This is not normal unless you start frame is not a keyframe\n");
        }
        return frame;
}
/**
    \fn getPCMPacket
*/
bool         ADM_edAudioTrackExternal::getPCMPacket(float  *dest, uint32_t sizeMax, uint32_t *samples,uint64_t *odts)
{
uint32_t fillerSample=0;   // FIXME : Store & fix the DTS error correctly!!!!
uint32_t inSize;
bool      drop=false;
uint32_t outFrequency=codec->getOutputFrequency();
 vprintf("[PCMPacketExt]  request TRK %d:%x\n",0,(long int)0);
again:
    *samples=0;
    // Do we already have a packet ?
    if(!packetBufferSize)
    {
        if(!refillPacketBuffer())
        {
            ADM_warning("Cannot refill\n");
            return false;
        }
    }
    // We do now
    vprintf("[PCMPacketExt]  Packet size %d, Got %d samples, time code %08lu  lastDts=%08lu delta =%08ld\n",
                packetBufferSize,packetBufferSamples,packetBufferDts,lastDts,packetBufferDts-lastDts);


    // If lastDts is not initialized....
    if(lastDts==ADM_AUDIO_NO_DTS) setDts(packetBufferDts);
    vprintf("Last Dts=%s\n",ADM_us2plain(lastDts));
    //
    //  The packet is ok, decode it...
    //
    uint32_t nbOut=0; // Nb sample as seen by codec
    vprintf("externalPCM: Sending %d bytes to codec\n",packetBufferSize);
    if(!codec->run(packetBuffer, packetBufferSize, dest, &nbOut))
    {
            packetBufferSize=0; // consume
            ADM_warning("[PCMPacketExt::getPCMPacket] Track %d:%x : codec failed failed\n", 0,0);
            return false;
    }
    packetBufferSize=0; // consume

    // Compute how much decoded sample to compare with what demuxer said
    uint32_t decodedSample=nbOut;
    decodedSample/=wavHeader.channels;
    if(!decodedSample) goto again;
#define ADM_MAX_JITTER 5000  // in samples, due to clock accuracy, it can be +er, -er, + er, -er etc etc
    if(labs((int64_t)decodedSample-(int64_t)packetBufferSamples)>ADM_MAX_JITTER)
    {
        ADM_warning("[PCMPacketExt::getPCMPacket] Track %d:%x Demuxer was wrong %d vs %d samples!\n",
                    0,0,packetBufferSamples,decodedSample);
    }
    
    // Update infos
    *samples=(decodedSample);
    *odts=lastDts;
    vprintf("externalPCM: got %d samples, PTS is now %s\n",decodedSample,ADM_us2plain(*odts));
    advanceDtsByCustomSample(decodedSample,outFrequency);
    vprintf("[Composer::getPCMPacket] Track %d:%x Adding %u decoded, Adding %u filler sample,"
        " dts is now %lu\n", 0,(long int)0,  decodedSample,fillerSample,lastDts);
    ADM_assert(sizeMax>=(fillerSample+decodedSample)*wavHeader.channels);
    vprintf("[getPCMext] %d samples, dts=%s\n",*samples,ADM_us2plain(*odts));
    return true;
}
Example #24
0
/**
    \fn addReferenceVideo
    \brief Add a new source video, fill in the missing info + create automatically the matching seg
*/
bool        ADM_EditorSegment::addReferenceVideo(_VIDEOS *ref)
{
  uint32_t    	l;
  uint8_t 	    *d;
  aviInfo       info;
  _SEGMENT      seg;

  ref->dontTrustBFramePts=ref->_aviheader->unreliableBFramePts();
  ref->_aviheader->getVideoInfo (&info);
  ref->_aviheader->getExtraHeaderData (&l, &d);
  ref->decoder = ADM_getDecoder (info.fcc,  info.width, info.height, l, d,info.bpp);
  ref->_videoCache   =   new EditorCache(8,info.width,info.height) ;

  float frameD=info.fps1000;
  frameD=frameD/1000;
  frameD=1/frameD;
  frameD*=1000000;
  ref->timeIncrementInUs=(uint64_t)frameD;

  // Probe the real time increment as the value determined from FPS may be incorrect due to interlace
  uint64_t firstNonZeroDts=ADM_NO_PTS,pts,dts;
  int firstNonZeroDtsFrame;
  ADM_info("[editor] Original frame increment %s\n",ADM_us2plain(ref->timeIncrementInUs));
  uint64_t minDelta=100000;
  uint64_t maxDelta=0;
  for (int frame=0; frame<info.nb_frames; frame++)
  {
      if (ref->_aviheader->getPtsDts(frame,&pts,&dts) && dts!=ADM_NO_PTS && dts!=0)
      {
          if (firstNonZeroDts==ADM_NO_PTS)
          {
              firstNonZeroDts=dts;
              firstNonZeroDtsFrame=frame;
              continue;
          }

          uint64_t probedTimeIncrement=(dts-firstNonZeroDts)/(frame-firstNonZeroDtsFrame);
          if(probedTimeIncrement<minDelta) minDelta=probedTimeIncrement;
          if(probedTimeIncrement>maxDelta) maxDelta=probedTimeIncrement;
          firstNonZeroDts=dts;
          firstNonZeroDtsFrame=frame;
      }
  }
  ADM_info("[Editor] min increment %s\n",ADM_us2plain(minDelta));
  ADM_info("[Editor] max increment %s\n",ADM_us2plain(maxDelta));
  
  //if (minDelta==ref->timeIncrementInUs*2)
              //ref->timeIncrementInUs=minDelta;

  
  ADM_info("[Editor] About %"PRIu64" microseconds per frame\n",ref->timeIncrementInUs);
  ref->_nb_video_frames = info.nb_frames;
  //
  //  And automatically create the segment
  //
  seg._reference=videos.size();
  if(!videos.size())
  {
        seg._startTimeUs=0;
  }else
  {
//      #warning todo compute cumulative time
   }
   seg._durationUs=ref->_aviheader->getVideoDuration();

    // Set the default startTime to the pts of first Pic
    vidHeader *demuxer=	ref->_aviheader;
    uint32_t flags;
        demuxer->getFlags(0,&flags);
        demuxer->getPtsDts(0,&pts,&dts);
        ref->firstFramePts=0;
        if(pts==ADM_NO_PTS) ADM_warning("First frame has unknown PTS\n");
        if(pts!=ADM_NO_PTS &&pts)
        {
            ADM_warning("The first frame has a PTS >0, adjusting to %"PRIu64" ms\n",pts/1000);
            ref->firstFramePts=pts;
        }

    if(!segments.empty()) undoSegments.push_back(segments);

    segments.push_back(seg);
    videos.push_back(*ref);
    updateStartTime();
    return true;
}
/**
        \fn getCompressedPicture
        \brief bypass decoder and directly get the source image

    The dropBframe is as follow :
            0 : Dont drop b frame
            1 : Follow the next bframes
            2 : Drop


*/
bool        ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressedImage *img)
{
    uint64_t tail;
    //
    int64_t signedPts;
    int64_t signedDts;

againGet:
    static uint32_t fn;
    fn++;
    _SEGMENT *seg=_segments.getSegment(_currentSegment);
    ADM_assert(seg);
    _VIDEOS *vid=_segments.getRefVideo(seg->_reference);
    ADM_assert(vid);
    vidHeader *demuxer=vid->_aviheader;
    ADM_assert(demuxer);

    // Get next pic?
    if(false==demuxer->getFrame (vid->lastSentFrame,img))
    {
        ADM_info("Failed to get next frame for ref %"PRIu32"\n",seg->_reference);
        goto nextSeg;
    }

    vid->lastSentFrame++;
    //
    aviInfo    info;
    vid->_aviheader->getVideoInfo (&info);
    //
    if(bFrameDroppable(info.fcc))
    {
        if(img->flags & AVI_B_FRAME)
        {
            if(seg->_dropBframes==2)
            {
                ADM_warning("%"PRIu32" Dropping bframes\n",fn);
                goto againGet;
            }
        } else
        {   // not a bframe
            switch(seg->_dropBframes)
            {
            case 2:
                seg->_dropBframes=0;
                break;
            case 1:
                seg->_dropBframes=2;
                break;
            default:
                break;
            }
        }
    }
    aprintf("Bframe droppable=%d, lastSentFrame=%d\n",seg->_dropBframes,vid->lastSentFrame);
    // after a segment switch, we may have some frames from "the past"
    // if the cut point is not a keyframe, drop them
#if 1
    if( img->demuxerDts!=ADM_NO_PTS)
    {
        bool drop=false;
        if(_currentSegment  && img->demuxerDts<seg->_refStartDts)
        {
            ADM_info("Frame %d is in the past for this segment (%s)",vid->lastSentFrame,ADM_us2plain(img->demuxerDts));
            ADM_info("vs refstartdts %s\n",ADM_us2plain(seg->_refStartDts));
            ADM_info(" dts=%llu, ref=%llu\n",img->demuxerDts,seg->_refStartDts);
            drop=true;
        }
        // Seeking is not accurate when cutting on non intra
        // we might have some frames that are clearly too early , even in seg0
        if(img->demuxerPts!=ADM_NO_PTS)
        {
            if(img->demuxerPts+seg->_startTimeUs<seg->_refStartTimeUs)
            {
                ADM_info("Frame %d is in the past for this segment -bis (%s)",vid->lastSentFrame,ADM_us2plain(img->demuxerPts));
                ADM_info("vs refstartdts %s\n",ADM_us2plain(seg->_refStartTimeUs));
                ADM_info(" pts=%llu, startTime=%llu, _refStartTimeUs=%llu\n",img->demuxerPts,seg->_startTimeUs,seg->_refStartTimeUs);
                drop=true;
            }
        }
        if(drop)
            goto againGet;

    }
#endif
    // Need to switch seg ?
    tail=seg->_refStartTimeUs+seg->_durationUs;
    // Guess DTS
    //
//**
    // ADM_info("Frame : Flags :%X, DTS:%"PRId64" PTS=%"PRId64" nextDts=%"PRId64" tail=%"PRId64"\n",img->flags,img->demuxerDts/1000,img->demuxerPts/1000,_nextFrameDts,tail);
    if(img->demuxerDts!= ADM_NO_PTS && img->demuxerDts>=tail)
    {
        aprintf("DTS is too late, switching (%s)\n",ADM_us2plain(img->demuxerDts));
        goto nextSeg;
    }
    if(img->demuxerPts!= ADM_NO_PTS && img->demuxerPts>=tail)
    {
        aprintf("PTS is too late, switching (%s)\n",ADM_us2plain(img->demuxerDts));
        goto nextSeg;
    }

    // Since we rely on PTS for seeking, frame 0 might be at PTS 0, in that case the matching dts would be <0
    // so the caller can delay everything but recalibrate will clamp the value
    // so we use correctedDts so that the value is ok
    if(img->demuxerDts==ADM_NO_PTS)
        signedDts=ADM_NO_PTS;
    else
    {
        signedDts=(int64_t)img->demuxerDts;
        recalibrateSigned(&(signedDts),seg);
    }

    if(img->demuxerPts==ADM_NO_PTS)
        signedPts=ADM_NO_PTS;
    else
    {
        signedPts=(int64_t)img->demuxerPts;
        recalibrateSigned(&(signedPts),seg);
    }

    // From here we are in linear time, guess DTS if missing...
    if(signedDts==ADM_NO_PTS)
    {
        // border case due to rounding we can have pts slighly above dts
        if(signedPts!=ADM_NO_PTS && _nextFrameDts!=ADM_NO_PTS)
        {
            signedDts=_nextFrameDts;
            if(signedPts != ADM_NO_PTS && signedDts>signedPts)
            {
                // not sure it is correct. We may want to do it the other way around, i.e. bumping pts
                ADM_warning("Compensating for rounding error with PTS=%"PRId64"ms DTS=%"PRId64"ms \n",signedPts,signedDts);
                signedPts=signedDts;
            }
        }
    } else
    {
// It means that the incoming image is earlier than the expected time.
// we add a bit of timeIncrement to compensate for rounding
        if(_nextFrameDts!=ADM_NO_PTS)
        {
            if(_nextFrameDts>signedDts+vid->timeIncrementInUs/10)
            {
                ADM_error("Frame %"PRIu32" DTS is going back in time : expected : %"PRId64" ms got : %"PRId64" ms\n",
                          fn,_nextFrameDts/1000,signedDts/1000);
            }
        }
        _nextFrameDts=signedDts;
    }
    // Increase for next one
    if(ADM_NO_PTS!=_nextFrameDts)
        _nextFrameDts+=vid->timeIncrementInUs;
    // Check the DTS is not too late compared to next seg beginning...
    if(_currentSegment+1<_segments.getNbSegments() && img->demuxerDts!=ADM_NO_PTS)
    {
        _SEGMENT *nextSeg=_segments.getSegment(_currentSegment+1);
        int64_t nextDts=nextSeg->_startTimeUs+nextSeg->_refStartDts;
        if(nextDts<nextSeg->_refStartTimeUs)
        {
            ADM_warning("%"PRIu32" next DTS is negative %"PRIu64" %"PRIu64" ms\n",fn,nextDts,nextSeg->_refStartTimeUs);
        } else
        {
            nextDts-=nextSeg->_refStartTimeUs;
            if(signedDts>=nextDts)
            {
                ADM_warning("%"PRIu32" have to switch segment, DTS limit reached %"PRIu64" %"PRIu64"\n",fn,img->demuxerDts/1000,nextDts/1000);
                goto nextSeg;
            }
        }


    }
// **
    // ADM_info("Frame after RECAL: Flags :%X, DTS:%"PRId64" PTS=%"PRId64" tail=%"PRId64"\n",img->flags,img->demuxerDts/1000,img->demuxerPts/1000,tail);
    img->demuxerDts=signedDts+videoDelay;
    img->demuxerPts=signedPts+videoDelay;
    return true;

nextSeg:
    if(false==switchToNextSegment(true))
    {
        ADM_warning("Cannot update to new segment\n");
        return false;
    }
    // Mark it as drop b frames...
    _SEGMENT *thisseg=_segments.getSegment(_currentSegment);
    thisseg->_dropBframes=1;
    ADM_info("Retrying for next segment\n");
    return getCompressedPicture(videoDelay,img);

}
/**
    \fn fillAudio
    \brief push audio packets until nextDts is reached
*/  
bool muxerMp4v2::fillAudio(uint64_t targetDts)
{
    for(int audioIndex=0;audioIndex<nbAStreams;audioIndex++)
    {
                ADM_audioStream         *a=aStreams[audioIndex];
                uint32_t                fq=a->getInfo()->frequency;
                mp4v2AudioPacket       *pkt=&(audioPackets[audioIndex]);
                audioClock             *clock=pkt->clock;
                if(pkt->eos)            continue;
                uint64_t                extraSamples=0;
                while(1)
                {
                        int current=!pkt->nextWrite;
                        int other=pkt->nextWrite;
                        mp4v2AudioPacket::mp4v2AudioBlock        *currentBlock=&(pkt->blocks[current]);
                        mp4v2AudioPacket::mp4v2AudioBlock        *otherBlock=&(pkt->blocks[other]);
                        // Get our currentDts
                        uint64_t currentDts=clock->getTimeUs();                        
                        uint64_t blockDts=currentBlock->dts;
                        if(pkt->eos)            break;
                        extraSamples=0;
                        // Take either block Dts or our own if no DTS is provided
                        if(currentBlock->dts!=ADM_NO_PTS)
                        {
                            bprintf("Current audio Dts=%"PRId64"\n",currentDts);
                            bprintf("Incoming block, dts=%"PRId64"\n",currentBlock->dts);
                            bprintf("Delta =%d ms\n",(int)(currentDts-currentBlock->dts));
                            if( labs((long int)currentBlock->dts-(long int)currentDts)>MP4V2_MAX_JITTER)
                            {
                                if(currentBlock->dts<currentDts)
                                    {
                                            ADM_warning("Audio going back in time audio track %d\n",audioIndex);
                                            ADM_warning("expected %d ms, got %d ms",currentDts/1000,currentBlock->dts/1000);
                                            ADM_warning("Dropping packet\n");
                                            goto nextOne;
                                    }
                                // We have a hole, increase duration of current packet
                                double holeDurationUs=currentBlock->dts-currentDts;
                                ADM_warning("Hole detected in audio of %d ms, track %d\n",(int)(holeDurationUs/1000),audioIndex);
                                ADM_warning("we got a timing of %s",ADM_us2plain(currentBlock->dts));
                                ADM_warning("and expected %s\n",ADM_us2plain(currentDts));
                                holeDurationUs*=fq;
                                holeDurationUs/=1000*1000;
                                ADM_warning("Increasing hole duration by %d samples\n",(int)holeDurationUs);
                                extraSamples=(uint64_t)holeDurationUs;
                            }
                        }else       
                            blockDts=currentDts;
                        if(blockDts>targetDts) // In the future
                            break;
                        if(false==writeAudioBlock(audioIndex,currentBlock,currentBlock->nbSamples+extraSamples))
                        {
                            ADM_error("Cannot write audio sample for track %d\n",audioIndex);
                            pkt->eos=true;
                            return false;
                        }
                        // load next

                        clock->advanceBySample(currentBlock->nbSamples+extraSamples);
nextOne:
                        if(false==loadAndToggleAudioSlot(audioIndex))
                        {
                            ADM_warning("End of audio stream %d\n",audioIndex);
                            #warning Purge other slot
                            pkt->eos=true;
                        }
                }
    }
    return true;
}
bool admSaver::save(void)
{


    int ret=false;
    
    
    ADM_info("Audio starting time %s\n",ADM_us2plain(startAudioTime));
    ADM_info("[A_Save] Saving..\n");
    
    const char *defaultExtension=ADM_MuxerGetDefaultExtension(muxerIndex);
    EditableAudioTrack *ed=NULL;
    ADM_info("Muxer default extension %s\n",defaultExtension);
    if(!videoEncoderIndex) 
    {
        if(false==video_body-> checkCutsAreOnIntra())
        {
            if(!GUI_Question("The video is in copy mode but the cut points are not on keyframes.\n"
                            "The video will be saved but there will corruption at cut point(s).\n"
                             "Do you want to continue anyway ?"))
            {
                return false;
            }
        }
    }

    if(!(muxer=ADM_MuxerSpawnFromIndex(muxerIndex)))
    {
        GUI_Error_HIG("Muxer","Cannot instantiante muxer");
        return 0;
    }
     
    ADM_videoStream *video=setupVideo();
    if(!video)
    {
        return false;
    }
    // adjust audio starting time
     for(int i=0;i<nbAudioTracks;i++)
        {
            ADM_audioStream  *stream=video_body->getAudioStreamAt(i);
            stream->goToTime(startAudioTime);
        }
    if(false==setupAudio())
    {
        if(video) delete video;
        if(muxer) delete muxer;
        muxer=NULL;
        return false;
    }
   
    // Check if we need to add an extension....
    if(defaultExtension)
    {
        if(!strstr(fileName.c_str(),"."))
        {
            
            fileName=fileName+std::string(".")+std::string(defaultExtension);
            ADM_info("Adding extension, filename is now %s\n",fileName.c_str());
        }

    }
    if(!muxer->open(fileName.c_str(),video,nbAudioTracks,audioAccess))
    {
        GUI_Error_HIG("Muxer","Cannot open ");
    }else
    {
        ret=muxer->save();
        muxer->close();
    }
abort123:
    if(video)
        delete video;
    video=NULL;
    for(int i=0;i<nbAudioTracks;i++)
    {
        delete audioAccess[i];
        audioAccess[i]=NULL;
    }
    return ret;
}
/**
    \fn save
*/
bool muxerAvi::save(void)
{
    printf("[AviMuxer] Saving\n");
    uint32_t bufSize=vStream->getWidth()*vStream->getHeight()*3;
    bool result=true;
   
    uint64_t rawDts;
    uint64_t lastVideoDts=0;
    int ret;
    int written=0;
   
    audioPackets=new aviAudioPacket[nbAStreams];
    videoBuffer=new uint8_t[bufSize];

    ADM_info("[AviMuxer]avg fps=%u\n",vStream->getAvgFps1000());
    ADMBitstream in(bufSize);
    in.data=videoBuffer;
    uint64_t aviTime=0;
    
    if(in.dts==ADM_NO_PTS) in.dts=0;
    lastVideoDts=in.dts;

    initUI("Saving Avi");
    encoding->setContainer("AVI/OpenDML");
    if(false==prefill(&in)) goto abt;
    while(1)
    {
            aprintf("Current clock=%s\n",ADM_us2plain(aviTime));
            aprintf("Video in dts=%s\n",ADM_us2plain(in.dts));
            if(in.dts>aviTime+videoIncrement)
            {
                aprintf("Too far in the future, writting dummy frame\n");
                writter.saveVideoFrame( 0, 0,videoBuffer); // Insert dummy video frame
                encoding->pushVideoFrame(0,0,in.dts);
            }else
            {
                aprintf("Writting video frame\n");
                if(!writter.saveVideoFrame( in.len, in.flags,videoBuffer))  // Put our real video
                {
                        ADM_warning("[AviMuxer] Error writting video frame\n");
                        result=false;
                        goto abt;
                }
                encoding->pushVideoFrame(in.len,in.out_quantizer,in.dts);
                if(false==vStream->getPacket(&in)) goto abt;
                if(in.dts==ADM_NO_PTS)
                {
                    in.dts=lastVideoDts+videoIncrement;
                }else
                    rescaleVideo(&in,firstPacketOffset);
                lastVideoDts=in.dts;
            }

            fillAudio(aviTime+videoIncrement);    // and matching audio

            if(updateUI()==false)
            {  
                result=false;
                goto abt;
            }
           
            written++;
            aviTime+=videoIncrement;
    }
abt:
    closeUI();
    writter.setEnd();
    delete [] videoBuffer;
    videoBuffer=NULL;
    delete [] audioPackets;
    audioPackets=NULL;
    ADM_info("[AviMuxer] Wrote %d frames, nb audio streams %d\n",written,nbAStreams);
    return result;
}
Example #29
0
/**
    \fn updateStartTime
    \brief Recompute the start time of the video
*/
bool         ADM_EditorSegment::updateStartTime(void)
{
    int n=segments.size();
    if(!n) return true;
    
    uint64_t t=0;
    t=segments[0]._startTimeUs;
    for(int i=0;i<n;i++)
    {
        segments[i]._startTimeUs=t;
        t+=segments[i]._durationUs;
    }
    // Now set the _refStartDts field
    for(int i=0;i<n;i++)
    {
        _VIDEOS *vid=getRefVideo(segments[i]._reference);
        _SEGMENT *seg=getSegment(i);
        vidHeader *demuxer=vid->_aviheader;


        uint64_t pts,dts;
        pts=seg->_refStartTimeUs;
        // Special case : If pts=0 it might mean beginning of seg i, but the PTS might be not 0
        // in such a case the DTS is wrong
        if(!pts)
        {
            uint64_t pts2,dts2;
            demuxer->getPtsDts(0,&pts2,&dts2);
            if(pts2!=ADM_NO_PTS)
            {
                ADM_info("Using pts2=%s to get dts, as this video does not start at zero\n",ADM_us2plain(pts2));
                pts=pts2;
            }

        }
        dtsFromPts(seg->_reference,pts,&dts);
        seg->_refStartDts=dts;
    }

    return true;
}
Example #30
0
/**
    \fn setup
*/
bool x265Encoder::setup(void)
{
    ADM_info("=============x265, setting up==============\n");
    MMSET(param);

    x265_param_default( &param);
    firstIdr=true;
    image=new ADMImageDefault(getWidth(),getHeight());

    // -------------- preset, tune, idc ------------
    if(!x265Settings.useAdvancedConfiguration)
    {
        char tune[200] = {0};
        strcat(tune, x265Settings.general.tuning);
        x265_param_default_preset(&param, x265Settings.general.preset, tune);
    }
    param.logLevel=x265Settings.level;

    // Threads..
#if X265_BUILD < 47
    switch(x265Settings.general.poolThreads)
    {
    case 0:
    case 1:
    case 2:
        param.poolNumThreads = x265Settings.general.poolThreads;
        break;
    case 99:
        break; //auto
    default:
        ADM_error("UNKNOWN NB OF THREADS\n");
        break;
    }
#endif

    switch(x265Settings.general.frameThreads)
    {
    case 0:
    case 1:
    case 2:
        param.frameNumThreads = x265Settings.general.frameThreads;
        break;
    case 99:
        break; //auto
    default:
        ADM_error("UNKNOWN NB OF THREADS\n");
        break;
    }
    param.sourceWidth = getWidth();
    param.sourceHeight = getHeight();
    param.internalCsp = X265_CSP_I420;
    param.internalBitDepth = 8;
    param.logLevel=X265_LOG_INFO; //DEBUG; //INFO;

    //Framerate
    int n,d;
    uint64_t f=source->getInfo()->frameIncrement;
    usSecondsToFrac(f,&n,&d);
    param.fpsNum = d;
    param.fpsDenom = n;

    // -------------- vui------------
#undef MKPARAM
#undef MKPARAMD
#undef MKPARAMB
#define MKPARAM(x,y) {param.vui.x = x265Settings.vui.y;aprintf("[x265] vui."#x" = %d\n",param.vui.x);}
#define MKPARAMD(x,y) {param.vui.x = (double)x265Settings.vui.y; aprintf("[x265] vui."#x" = %.2f\n",param.vui.x);}
#define MKPARAMB(x,y) {param.vui.x = x265Settings.vui.y ;aprintf("[x265] vui."#x" = %s\n",TrueFalse[param.vui.x&1]);}
    MKPARAM (sarWidth,sar_width)
    MKPARAM (sarHeight,sar_height)

    // -------------- rate control------------
    switch(x265Settings.general.params.mode)
    {
    case COMPRESS_2PASS:
    case COMPRESS_2PASS_BITRATE:
        uint32_t bitrate;
        if(passNumber!=1 && passNumber!=2)
        {
            ADM_error("No pass number specified! (%d)\n",(int)passNumber);
            return false;
        }
        ADM_info("Starting pass :%d\n",passNumber);
        if(x265Settings.general.params.mode==COMPRESS_2PASS)
        {
            uint64_t duration=source->getInfo()->totalDuration; // in us
            ADM_info("Source duration :%s\n",ADM_us2plain(duration));
            ADM_info("Target size     :%d\n",(int)x265Settings.general.params.finalsize);
            uint32_t avg;
            if(false==ADM_computeAverageBitrateFromDuration(duration,
                    x265Settings.general.params.finalsize,
                    &avg))
            {
                ADM_error("[x265] No source duration!\n");
                return false;
            }
            bitrate=(uint32_t)avg;
        }
        else
            bitrate=x265Settings.general.params.avg_bitrate;
        ADM_info("Using average bitrate of %d kb/s\n",(int)bitrate);
        param.rc.rateControlMode = X265_RC_ABR;
        param.rc.bitrate =  bitrate;
        if(passNumber==1)
        {
            param.rc.bStatWrite=1;
            param.rc.bStatRead=0;
            param.rc.statFileName=strdup(logFile);

        } else
        {
            param.rc.bStatWrite=0;
            param.rc.bStatRead=1;
            param.rc.statFileName=strdup(logFile);
            if(!ADM_fileExist(logFile))
            {
                ADM_error("Logfile %s does not exist \n",logFile);
                return false;
            }
        }
        break;
    case COMPRESS_AQ:
        param.rc.rateControlMode = X265_RC_CRF;
        param.rc.rfConstant = x265Settings.general.params.qz;
        break;
    case COMPRESS_CQ:
        param.rc.rateControlMode = X265_RC_CQP;
        param.rc.qp = x265Settings.general.params.qz;
        break;

    case COMPRESS_CBR:
        param.rc.rateControlMode = X265_RC_ABR;
        param.rc.bitrate =  x265Settings.general.params.bitrate;
        param.rc.qp = 0;
        param.rc.rfConstant = 0;
        break;
    default:
        GUI_Error_HIG("Not coded","this mode has notbeen implemented\n");
        return false;
        break;

    }

    if(globalHeader)
        param.bRepeatHeaders=0;
    else
        param.bRepeatHeaders=1;

    if(x265Settings.useAdvancedConfiguration)
    {

#undef MKPARAM
#undef MKPARAMD
#undef MKPARAMB
#define MKPARAM(x,y) {param.x = x265Settings.y;aprintf("[x265] "#x" = %d\n",param.x);}
#define MKPARAMD(x,y) {param.x = (double)x265Settings.y; aprintf("[x265] "#x" = %.2f\n",param.x);}
#define MKPARAMB(x,y) {param.x = x265Settings.y ;aprintf("[x265] "#x" = %s\n",TrueFalse[param.x&1]);}
        MKPARAM(maxNumReferences,MaxRefFrames);
        MKPARAM(keyframeMin,MinIdr);
        MKPARAM(keyframeMax,MaxIdr);
        MKPARAM(scenecutThreshold,i_scenecut_threshold);
        MKPARAM(bframes,MaxBFrame);

        MKPARAM(bFrameAdaptive,i_bframe_adaptive);
        MKPARAM(bFrameBias,i_bframe_bias);
        MKPARAM(bBPyramid,i_bframe_pyramid);
        MKPARAMB(bEnableLoopFilter,b_deblocking_filter);
        MKPARAMB(interlaceMode,interlaced_mode);
        MKPARAMB(bEnableConstrainedIntra,constrained_intra);
        MKPARAM(lookaheadDepth,lookahead);

        MKPARAMB(bEnableWeightedBiPred,weighted_bipred)
        MKPARAM (bEnableWeightedPred,weighted_pred)
        MKPARAM (cbQpOffset,cb_chroma_offset)
        MKPARAM (crQpOffset,cr_chroma_offset)

        MKPARAM (searchMethod,me_method)
        MKPARAM (searchRange,me_range)
        MKPARAM (subpelRefine,subpel_refine)
        MKPARAM (bFrameAdaptive,trellis)
        MKPARAMB(bEnableEarlySkip,fast_pskip)
        MKPARAMB(bEnableTSkipFast,dct_decimate)
        MKPARAMD(psyRd,psy_rd)

#if X265_BUILD >= 40
        MKPARAM (noiseReductionIntra,noise_reduction_intra)
        MKPARAM (noiseReductionInter,noise_reduction_inter)
#else
        MKPARAM (noiseReduction,noise_reduction)
#endif

        //---------------- ratecontrol -------------------
#undef MKPARAM
#undef MKPARAMD
#undef MKPARAMB
#define MKPARAM(x,y)  {param.rc.x = x265Settings.ratecontrol.y;aprintf("[x265] rc."#x" = %d\n",param.rc.x);}
#define MKPARAMD(x,y) {param.rc.x = (double)x265Settings.ratecontrol.y; aprintf("[x265] rc."#x" = %.2f\n",param.rc.x);}
#define MKPARAMB(x,y) {param.rc.x = x265Settings.ratecontrol.y ;aprintf("[x265] rc."#x" = %s\n",TrueFalse[param.rc.x&1]);}

        MKPARAM(qpStep,qp_step);

#if X265_BUILD >= 41
        MKPARAMB(bStrictCbr,strict_cbr);
#else
        MKPARAM(rateTolerance,rate_tolerance);
#endif

        MKPARAM(ipFactor,ip_factor);
        MKPARAM(pbFactor,pb_factor);
        MKPARAMB(cuTree,cu_tree);
        MKPARAM(aqMode,aq_mode);
        MKPARAMD(aqStrength,aq_strength);
    }

    if(!param.bframes)  encoderDelay=0;
    else
    {
        if(2>=param.maxNumReferences)
        {
            encoderDelay=f*2*2;
        }
        else
        {
            encoderDelay=2*f*(x265Settings.MaxRefFrames-1);
        }
    }

    if(!x265Settings.useAdvancedConfiguration)
    {
        x265_param_apply_profile(&param, x265Settings.general.profile);
    }

    dumpx265Setup(&param);
    ADM_info("Creating x265 encoder\n");
    handle = x265_encoder_open (&param);
    if (!handle)
    {
        ADM_error("Cannot initialize x265\n");
        return 0;
    }


    ADM_info("x265, setup ok\n");
    if (globalHeader)
    {
        ADM_info("Creating global header\n");
        return createHeader ();
    } else
        ADM_info("No need for global header\n");

    return true;
}