"Fossies" - the Fresh Open Source Software archive

Member "wxcam-1.1/src/xvidcodec.cpp" of archive wxcam-1.1.tar.gz:


/***************************************************************************
 *   Copyright (C) 2007 by Marco Lorrai                                    *
 *   marco.lorrai@abbeynet.it                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "xvidcodec.h"
#include <iostream>
#include <wx/event.h>
#include "frame.h"
#include "audio.h"

#define CHANNELS 2
#define RATE 44100

using namespace std;

Xvid::Xvid() : cond(mutex) 
{
    frameNumber=0; 
    audioFramesRecorded=0;
    compression=0.5f;
    audio=NULL;
    ignoreVideo = false;
    endRecord = false;
    max=0;
}

Xvid::~Xvid()
{
}

int Xvid::setup()
{
    if (REVEL_API_VERSION != Revel_GetApiVersion())
    {
        cout<<"ERROR: Revel version mismatch!"<<endl;
        printf("Headers: version %06x, API version %d\n", REVEL_VERSION,
            REVEL_API_VERSION);
        printf("Library: version %06x, API version %d\n", Revel_GetVersion(),
            Revel_GetApiVersion());
        return 1;
    }     
           
    revError = Revel_CreateEncoder(&encoderHandle);
    if (revError != REVEL_ERR_NONE)
    {
        printf("Revel Error while creating encoder: %d\n", revError);
        return 1;
    }
    
    Revel_Params revParams;
    Revel_InitializeParams(&revParams);
    revParams.width = width;
    revParams.height = height;
    revParams.frameRate = fps;
    revParams.quality = compression;
    revParams.codec = REVEL_CD_XVID;

    hasAudio = checkAudio(&revParams);

    revError = Revel_EncodeStart(encoderHandle, filename.c_str(), &revParams);
    if (revError != REVEL_ERR_NONE)
    {
        printf("Revel Error while starting encoding: %d\n", revError);
        return 1;
    }                  
    
    revelFrame.width = width;
    revelFrame.height = height;
    revelFrame.bytesPerPixel = 4;
    revelFrame.pixelFormat = REVEL_PF_RGBA;
    revelFrame.pixels = new int[width*height];
    memset(revelFrame.pixels, 0, width*height*4);        
    
    return 0;
}

void Xvid::addFrame(const char* frame)
{
    if(!frameNumber) {
        if(hasAudio) {
            audioBufferSize = audio->startAcquisition(CHANNELS, RATE);
            if (audio->Create() != wxTHREAD_NO_ERROR ) {
                cout<<"Can't create audio recording thread!";
                return;
            }        
            audio->Run();
            addSilence(Setting::GetInstance()->GetSilence());
        }
    }

    mutex.Lock();
    queue.push_back(std::string(frame, frameSize));
        
        /*revError = Revel_EncodeFrame(encoderHandle, &revelFrame, &frameSize);
        if (revError != REVEL_ERR_NONE)
            printf("Revel Error while writing frame: %d\n", revError);*/
    
    
    /*encoding audio*/    
    if(hasAudio) {        
        std::vector<std::string> vectAudio = audio->getAudioFrames();
        audio_queue.push_back(vectAudio);
        /*int size = vectAudio.size();
        std::vector<std::string>::iterator it = vectAudio.begin();
        for(int i=1; i<=size; i++) {                       
            std::string buffer = *it;  
            ++it;
            audioFramesRecorded++;
            revError = Revel_EncodeAudio(encoderHandle, (void*)buffer.c_str(), buffer.size(), &totalAudioBytes);
            if (revError != REVEL_ERR_NONE) {
                printf("Revel Error while writing audio: %d\n", revError);
            }            
        }
        */

    }
    cond.Signal();
    mutex.Unlock();
    frameNumber++;
}

void* Xvid::Entry() {
    while(true) {
        mutex.Lock();
        while( (!queue.size() || !audio_queue.size())&& !endRecord)
            cond.Wait();
        //cout<<"Queue size: "<<queue_size<<endl<<flush;
        if(endRecord && (!queue.size() || !audio_queue.size())) { //registration terminated
            mutex.Unlock();
            
            break;
        }

        string videoFrame = queue.front();
        queue.pop_front();
        vector<string> audioFrames;        
        if(hasAudio) {
            audioFrames = audio_queue.front();
            audio_queue.pop_front();
        }

        //max not yet initialize, first execution after calling record()
        if(endRecord && !max) {
            max = queue.size();
            if(max > 10) {
                wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, PROGRESS_DIALOG_START );
                wxPostEvent( parent, event );
            }
            else
                max=-1;
        }

        //max already initialized
        if(endRecord && max > 0) {
            wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, PROGRESS_DIALOG_EVENT );
            int n = (int)(((float)max - (float)queue.size()) / (float)max * 100);
            event.SetInt( n );

            // send in a thread-safe way
            wxPostEvent( parent, event );
        }

        mutex.Unlock();

        int frameSize;
        const char* frame = videoFrame.c_str();        
        //writing frame...
        memcpy4( (char*)revelFrame.pixels, frame, width*height*4 );
        revError = Revel_EncodeFrame(encoderHandle, &revelFrame, &frameSize);
        if (revError != REVEL_ERR_NONE)
            printf("Revel Error while writing frame: %d\n", revError);

        if (hasAudio) {
            int totalAudioBytes;
            int size = audioFrames.size();
            std::vector<std::string>::iterator it = audioFrames.begin();
            for (int i = 1; i <= size; i++) {
                std::string buffer = *it;
                ++it;
                audioFramesRecorded++;
                revError = Revel_EncodeAudio(encoderHandle, (void*) buffer.c_str(), audioBufferSize, &totalAudioBytes);
                if (revError != REVEL_ERR_NONE) {
                    printf("Revel Error while writing audio: %d\n", revError);
                }
                //printf("Recorded %d audio frames total\n", size);
            }
        }
    }
    if(max > 0) {
        wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, PROGRESS_DIALOG_EVENT );

        event.SetInt(-1); // that's all
        wxPostEvent( parent, event );
    }
    wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, STOP_REC );
    event.SetInt(0);
    wxPostEvent( parent, event );
    return NULL;
}

bool Xvid::checkAudio(Revel_Params *revParams)
{
    int ret;

    hasAudio = true;

    if (hasAudio) {
        audio = new Audio();
        ret = audio->Open();
        if (ret < 0) {
            hasAudio = false;
            /*error to screen*/
            wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, AUDIO_ERR);
            event.SetInt(1);
            wxPostEvent(parent, event);
            audio->Delete();
            audio = NULL;
        } else {
            revParams->audioChannels = CHANNELS;
            revParams->audioRate = RATE;
            revParams->audioBits = 16;
            revParams->audioSampleFormat = REVEL_ASF_PCM;
        }
        revParams->hasAudio = hasAudio;
    }

    return hasAudio;
}

void Xvid::record()
{
    /*stopping audio acquisition*/
    if(hasAudio) {
        audio->stopAcquisition();
        audio->Wait();
    }
    
    int totalSize;
    revError = Revel_EncodeEnd(encoderHandle, &totalSize);
    if (revError != REVEL_ERR_NONE)
    {
        printf("Revel Error while ending encoding: %d\n", revError);
        exit(1);
    }
    printf("%s written: %dx%d, %d bytes\n", filename.c_str(), width, height, totalSize);

    // Final cleanup.
    Revel_DestroyEncoder(encoderHandle);
    delete [] (int*)revelFrame.pixels;
    if(audio)
        audio->Delete(); 
    wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, STOP_REC );
    event.SetInt(0);
    wxPostEvent( parent, event );
}

void Xvid::memcpy4(char* dest, const char* src, int size)
{
    int j = 0;
    for(int i=0; i<size; i = i + 4) {
        memcpy(dest + i, src + j, 3);
        dest[i+3] = 0;
        j = j + 3;
    }
}

void Xvid::addSilence(int hundredthsSecond)
{
    int audioBufferSize = hundredthsSecond*882*CHANNELS; //2 is the number of channels;
    int totalAudioBytes;
    char* buffer = new char[audioBufferSize];
    memset(buffer, 0, audioBufferSize);
    revError = Revel_EncodeAudio(encoderHandle, (void*)buffer, audioBufferSize, &totalAudioBytes);
    if (revError != REVEL_ERR_NONE) {
        printf("Revel Error while writing audio: %d\n", revError);
    }
    //else
        //printf("Silence added\n");
    delete [] buffer;
}

void Xvid::setCompressionLevel(float level)
{
    compression = level;
}