织梦CMS - 轻松建站从此开始!

罗索

encode YUV420 to ogg, theora codec

jackyhwei 发布于 2011-07-06 09:28 点击:次 
将YUV420编码成OGG格式的代码实现(使用theora codec)
TAG:

#include <stdio.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include "theora/theoraenc.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisenc.h"

FILE *audio=NULL;
FILE *video=NULL;

int audio_ch=0;
int audio_hz=0;

float audio_q=.1f;
int audio_r=-1;

int frame_w=0;
int frame_h=0;
int pic_w=0;
int pic_h=0;
int pic_x=0;
int pic_y=0;
int video_fps_n=-1;
int video_fps_d=-1;
int video_par_n=-1;
int video_par_d=-1;
int src_c_dec_h=2;
int src_c_dec_v=2;
int dst_c_dec_h=2;
int dst_c_dec_v=2;

size_t y4m_dst_buf_sz;
size_t y4m_dst_buf_read_sz;

int video_r=-1;
int video_q=-1;
ogg_uint32_t keyframe_frequency=0;
int buf_delay=-1;

void init_param()
{
    audio_ch = 2;
    audio_hz = 44100;
    
    pic_w = 384;
    pic_h = 288;
    video_fps_n = 25;
    video_fps_d = 1;
    video_par_n = 0;
    video_par_d = 0;
    src_c_dec_h = 2;
    dst_c_dec_h = 2;
    src_c_dec_v = 2;
    dst_c_dec_v = 2;
    y4m_dst_buf_read_sz = pic_w*pic_h+2*((pic_w+1)/2)*((pic_h+1)/2);
    y4m_dst_buf_sz = pic_w*pic_h+2*((pic_w+dst_c_dec_h-1)/dst_c_dec_h)*((pic_h+dst_c_dec_v-1)/dst_c_dec_v);
}

int fetch_and_process_audio(FILE *audio,
                            ogg_page *audiopage,
                            ogg_stream_state *vo,
                            vorbis_dsp_state *vd,
                            vorbis_block *vb,
                            int audioflag)
{
    static ogg_int64_t samples_sofar=0;
    ogg_packet op;
    int i,j;
    while(audio && !audioflag)
    {
        if(ogg_stream_pageout(vo,audiopage)>0)
            return 1;
        if(ogg_stream_eos(vo))
            return 0;
        signed char readbuffer[4096];
        signed char *readptr=readbuffer;
        int toread=4096/2/audio_ch;
        int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio);
        int sampread=bytesread/2/audio_ch;
        float **vorbis_buffer;
        int count=0;

          if(bytesread<=0)
        {
            vorbis_analysis_wrote(vd,0);
        }
        else
        {
            
              samples_sofar += sampread;
            if(sampread>0)
            {
                  vorbis_buffer=vorbis_analysis_buffer(vd,sampread);
                  /* uninterleave samples */
                  for(i=0;i<sampread;i++)
                  {
                    for(j=0;j<audio_ch;j++)
                    {
                          vorbis_buffer[j][i]=((readptr[count+1]<<8)|(0x00ff&(int)readptr[count]))/32768.f;
                          count+=2;
                    }
                  }
                  vorbis_analysis_wrote(vd,sampread);
            }
        }

        while(vorbis_analysis_blockout(vd,vb)==1)
        {
            /* analysis, assume we want to use bitrate management */
            vorbis_analysis(vb,NULL);
            vorbis_bitrate_addblock(vb);
            /* weld packets into the bitstream */
            while(vorbis_bitrate_flushpacket(vd,&op))
                  ogg_stream_packetin(vo,&op);
        }
    }
      return audioflag;
}

static int                 frame_state=-1;
static unsigned char      *yuvframe[2];
static th_ycbcr_buffer     ycbcr;

int fetch_and_process_video_packet(FILE *video,th_enc_ctx *td,ogg_packet *op)
{    
    int                        ret;
    int                        pic_sz;
    int                        frame_c_w;
    int                        frame_c_h;
    int                        c_w;
    int                        c_h;
    int                        c_sz;
    
    if(frame_state==-1)
    {
        yuvframe[0]=(unsigned char *)malloc(y4m_dst_buf_sz);
        yuvframe[1]=(unsigned char *)malloc(y4m_dst_buf_sz);
        frame_state=0;
    }
    pic_sz=pic_w*pic_h;
    frame_c_w=frame_w/dst_c_dec_h;
    frame_c_h=frame_h/dst_c_dec_v;
    c_w=(pic_w+dst_c_dec_h-1)/dst_c_dec_h;
    c_h=(pic_h+dst_c_dec_v-1)/dst_c_dec_v;
    c_sz=c_w*c_h;

    for(;frame_state<2;)
    {
        char c,frame[6];
        int ret=fread(frame,1,6,video);
        if(ret<6)break;
        if(memcmp(frame,"FRAME\n",6))
        {
              fprintf(stderr,"Loss of framing in YUV input data\n");
              exit(1);
        }
        /*Read the frame data that needs no conversion.*/
        if(fread(yuvframe[frame_state],1,y4m_dst_buf_read_sz,video)!= y4m_dst_buf_read_sz)
         {
              fprintf(stderr,"Error reading YUV frame data.\n");
              exit(1);
        }
        frame_state++;
    }
    ycbcr[0].width=frame_w;
    ycbcr[0].height=frame_h;
    ycbcr[0].stride=pic_w;
    ycbcr[0].data=yuvframe[0]-pic_x-pic_y*pic_w;
    ycbcr[1].width=frame_c_w;
    ycbcr[1].height=frame_c_h;
    ycbcr[1].stride=c_w;
    ycbcr[1].data=yuvframe[0]+pic_sz-(pic_x/dst_c_dec_h)-(pic_y/dst_c_dec_v)*c_w;
    ycbcr[2].width=frame_c_w;
    ycbcr[2].height=frame_c_h;
    ycbcr[2].stride=c_w;
    ycbcr[2].data=ycbcr[1].data+c_sz;
    th_encode_ycbcr_in(td,ycbcr);
    {
        unsigned char *temp=yuvframe[0];
        yuvframe[0]=yuvframe[1];
        yuvframe[1]=temp;
        frame_state--;
    }
    if(frame_state<1)
    {
        printf("The last frame-----------------------------\n");
    }
    /* if there was only one frame, it's the last in the stream */
    ret = th_encode_packetout(td,frame_state<1,op);
    return ret;
}

int fetch_and_process_video(FILE *video,
                            ogg_page *videopage,
                            ogg_stream_state *to,
                            th_enc_ctx *td,
                            int videoflag)
{
    ogg_packet op;
    int ret;
    /* is there a video page flushed?  If not, work until there is. */
    while(!videoflag)
    {
        if(ogg_stream_pageout(to,videopage)>0)
            return 1;
        if(ogg_stream_eos(to))
        {
            printf("E\n") ;
            return 0;
        }
        ret=fetch_and_process_video_packet(video,td,&op);
        if(ret<=0)
            return 0;
        ogg_stream_packetin(to,&op);
    }
    return videoflag;
}

static int ilog(unsigned _v)
{
    int ret;
    for(ret=0;_v;ret++)
        _v>>=1;
    return ret;
}

long GetTickCount()
{
    struct timeval tv;

    gettimeofday(&tv, NULL);

    return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}

int main(int argc,char *argv[])
{
    int c,long_option_index,ret;

    ogg_stream_state to; /* take physical pages, weld into a logical stream of packets */
    ogg_stream_state vo; /* take physical pages, weld into a logical stream of packets */
    ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
    ogg_packet       op; /* one raw packet of data for decode */

    th_enc_ctx      *td;
    th_info          ti;
    th_comment       tc;

    vorbis_info      vi; /* struct that stores all the static vorbis bitstream settings */
    vorbis_comment   vc; /* struct that stores all the user comments */

    vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
    vorbis_block     vb; /* local working space for packet->PCM decode */

    int speed=-1;
    int audioflag=0;
    int videoflag=0;
    int akbps=0;
    int vkbps=0;

    ogg_int64_t audio_bytesout=0;
    ogg_int64_t video_bytesout=0;
    double timebase;

    FILE *outfile = fopen("out.ogv", "wb");

    fpos_t video_rewind_pos;
    long cur_time = 0;
 
      audio_q=(float)(3*.099);//-1 to 10, now is 3
    video_q=(int)rint(6.3*5);//0 to 10, now is 5
    keyframe_frequency=64;
    speed=2;
    
    video = fopen("video.dat", "rb");
    audio = fopen("audio.dat", "rb");
    init_param();
        
    srand(time(NULL));
    ogg_stream_init(&to,rand()); /* oops, add one ot the above */

    /* initialize Vorbis assuming we have audio to compress. */
    if(audio)
    {
        ogg_stream_init(&vo,rand());
        vorbis_info_init(&vi);
        if(audio_q>-99)
          ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q);
        else
          ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,
                                   (int)(64870*(ogg_int64_t)audio_r>>16),-1);
        if(ret){
          fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n"
                  "the requested quality or bitrate.\n\n");
          exit(1);
        }

        vorbis_comment_init(&vc);
        vorbis_analysis_init(&vd,&vi);
        vorbis_block_init(&vd,&vb);
    }
    /* Theora has a divisible-by-sixteen restriction for the encoded frame size */
    /* scale the picture size up to the nearest /16 and calculate offsets */
    frame_w=pic_w+15&~0xF;
    frame_h=pic_h+15&~0xF;
    /*Force the offsets to be even so that chroma samples line up like we
       expect.*/
    pic_x=frame_w-pic_w>>1&~1;
    pic_y=frame_h-pic_h>>1&~1;
    th_info_init(&ti);
    ti.frame_width=frame_w;
    ti.frame_height=frame_h;
    ti.pic_width=pic_w;
    ti.pic_height=pic_h;
    ti.pic_x=pic_x;
    ti.pic_y=pic_y;
    ti.fps_numerator=video_fps_n;
    ti.fps_denominator=video_fps_d;
    ti.aspect_numerator=video_par_n;
    ti.aspect_denominator=video_par_d;
    ti.colorspace=TH_CS_UNSPECIFIED;
    ti.target_bitrate=(int)(64870*(ogg_int64_t)video_r>>16);
    ti.quality=video_q;
    ti.keyframe_granule_shift=ilog(keyframe_frequency-1);
    ti.pixel_fmt=TH_PF_420;

    td=th_encode_alloc(&ti);
    th_info_clear(&ti);
    ret=th_encode_ctl(td,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,  &keyframe_frequency,sizeof(keyframe_frequency-1));
    if(ret<0)
    {
          fprintf(stderr,"Could not set keyframe interval to %d.\n",(int)keyframe_frequency);
    }
    
    if(buf_delay>=0)
    {
          ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_BUFFER, &buf_delay,sizeof(buf_delay));
          if(ret<0)
          {
            fprintf(stderr,"Warning: could not set desired buffer delay.\n");
          }
    }
    /*Speed should also be set after the current encoder mode is established,
       since the available speed levels may change depending.*/
    if(speed>=0)
    {
        int speed_max;
        int ret;
        ret=th_encode_ctl(td,TH_ENCCTL_GET_SPLEVEL_MAX, &speed_max,sizeof(speed_max));
        if(ret<0)
        {
            fprintf(stderr,"Warning: could not determine maximum speed level.\n");
            speed_max=0;
        }
        ret=th_encode_ctl(td,TH_ENCCTL_SET_SPLEVEL,&speed,sizeof(speed));
        if(ret<0)
        {
            fprintf(stderr,"Warning: could not set speed level to %i of %i\n", speed,speed_max);
            if(speed>speed_max)
            {
                  fprintf(stderr,"Setting it to %i instead\n",speed_max);
            }
            ret=th_encode_ctl(td,TH_ENCCTL_SET_SPLEVEL, &speed_max,sizeof(speed_max));
            if(ret<0)
            {
                  fprintf(stderr,"Warning: could not set speed level to %i of %i\n",speed_max,speed_max);
            }
        }
    }
    /* write the bitstream header packets with proper page interleave */
    th_comment_init(&tc);
    /* first packet will get its own page automatically */
    if(th_encode_flushheader(td,&tc,&op)<=0)
    {
          fprintf(stderr,"Internal Theora library error.\n");
          exit(1);
    }

     ogg_stream_packetin(&to,&op);
      if(ogg_stream_pageout(&to,&og)!=1)
      {
        fprintf(stderr,"Internal Ogg library error.\n");
        exit(1);
      }
      fwrite(og.header,1,og.header_len,outfile);
      fwrite(og.body,1,og.body_len,outfile);
(carlsonlee_freec)

本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201107/14668.html]
本文出处:hi.baidu.com/carlsonlee_freec 作者:carlsonlee_freec
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容