分享

将摄像头原始RGB数据流编码成H.264文件

 SamBookshelf 2013-07-16
复制代码

extern "C"
{
#include "avcodec.h"
#include "avformat.h"
#include "avio.h"
#include "avutil.h"
#include "common.h"
#include "intfloat_readwrite.h"
#include "inttypes.h"
#include "log.h"
#include "mathematics.h"
#include "mem.h"
#include "rational.h"
#include "stdint.h"
#include "swscale.h"
}

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#define RGBTOYUV(B, G, R, Y, U, V) \
Y = ( ( 66 * R   129 * G   25 * B   128) >> 8)   16;U = ( ( -38 * R - 74 * G   112 * B   128) >> 8)   128;V = ( ( 112 * R - 94 * G - 18 * B   128) >> 8)   128;

size_t BufSize = 9437184;
BYTE *pStream = new BYTE[BufSize];
BYTE* pBmp24;
int CALLBACK SnapThreadCallback(BYTE *pBuffer) //摄像头显示回调函数
{

pBmp24 = CameraISP(pBuffer);
if(pBmp24)
{
if (bVideo)
{
memcpy(pStream, pBmp24, BufSize);
}
CameraDisplayRGB24(pBmp24);
}
return TRUE;
}

void CXXDlg::OnBtnVideo() 
{
    // TODO: Add your control notification handler code here
    //CWinThread *pVedioStart;
    if (m_VideoMode != VIDEOMODE_PLAY)
    {
        GetDlgItem(IDC_BTN_VIDEO)->SetWindowText("停止录像");    
        AfxBeginThread((AFX_THREADPROC)VIDEO, this, THREAD_PRIORITY_ABOVE_NORMAL, 0, NULL);
        m_VideoMode = VIDEOMODE_PLAY;        
    }
    else
    {
        m_VideoMode = VIDEOMODE_STOP;
        GetDlgItem(IDC_BTN_VIDEO)->SetWindowText("开始录像");        
    }
}

UINT VIDEO(LPVOID pParam)
{
    CXXDlg * dlg = (CXXDlg *)pParam;
    BYTE* yuv = new BYTE[bufzise * 3 / 2];
    CString svideofile; 
    CTime time = CTime::GetCurrentTime();
    svideofile.Format("%02d%02d%02d%02d%02d", time.GetMonth(), time.GetDay(), 
        time.GetHour(), time.GetMinute(), time.GetSecond());
    CFile file(svideofile, CFile::modeWrite|CFile::modeCreate);
    int m_frame_count = 0;
    Sleep(100);
    bVideo = TRUE;
    while(dlg->m_VideoMode != VIDEOMODE_STOP)
    {
        if (StreamOK)
        {
            dlg->RGB2YUV(&pStream, &yuv, 3, ImgW, ImgH);
            memset(lpCurrentImage, 0, bufzise * 3);
            file.SeekToEnd();
            file.Write(yuv, bufzise*3/2);
            m_frame_count  ;
        }        
    }
    file.Close();
    dlg->SaveToH264(svideofile, ImgW, ImgH, m_frame_count);
    AfxMessageBox("录像已保存!");
    
    return 0;
}

void CXXDlg::RGB2YUV(BYTE** rgb, BYTE** yuv, unsigned rgbIncrement, int nWidth, int nHeight)
{
    unsigned width    = nWidth;  // 图像宽度
    unsigned height    = nHeight; // 图像高度    
    const unsigned planeSize = width*height;
    const unsigned halfWidth = width >> 1;
    unsigned count = 0;

    BYTE * yplane  = *yuv;
    BYTE * uplane  = *yuv   planeSize;
    BYTE * vplane  = *yuv   planeSize   (planeSize >> 2);
    BYTE * rgbIndex = *rgb;
    
    for (unsigned y = 0; y < height; y  ) 
    {
        BYTE * yline  = yplane   (y * width);
        BYTE * uline  = uplane   ((y >> 1) * halfWidth);
        BYTE * vline  = vplane   ((y >> 1) * halfWidth);
                
        rgbIndex = *rgb   (width*(height-1-y)*rgbIncrement); //将图像翻转

        for (unsigned x = 0; x < width; x =2) 
        {
            RGBTOYUV(rgbIndex[0], rgbIndex[1], rgbIndex[2], *yline, *uline, *vline);            
            rgbIndex  = rgbIncrement; count  ;
            yline  ;
            RGBTOYUV(rgbIndex[0], rgbIndex[1], rgbIndex[2],*yline, *uline, *vline);
            rgbIndex  = rgbIncrement; count  ;
            yline  ;
            uline  ;
            vline  ;
        }
    }
}

BOOL CXXDlg::SaveToH264 (CString YUVfile, int vWidth, int vHeight, int count)
{
    AVFormatContext* oc;
    AVOutputFormat* fmt;
    AVStream* video_st;
    double video_pts;
    uint8_t* video_outbuf;
    uint8_t* picture_buf;
    AVFrame* picture;
    int size;
    int ret;
    int video_outbuf_size;    
    CString s;
    s = YUVfile   ".avi";
    const char *videofile = s.GetBuffer(0);
    s.ReleaseBuffer();
    FILE *fin = fopen(YUVfile, "rb"); 
       CFile::modeWrite|CFile::modeCreate);

    av_register_all();

    fmt = guess_format(NULL, videofile, NULL);
    oc = av_alloc_format_context();
    oc->oformat = fmt;
    snprintf(oc->filename, sizeof(oc->filename), "%s", videofile);

    video_st = NULL;
    if (fmt->video_codec != CODEC_ID_NONE)
    {
        AVCodecContext* c;
        video_st = av_new_stream(oc, 0);
        c = video_st->codec;
        c->codec_id = fmt->video_codec;
        c->codec_type = CODEC_TYPE_VIDEO;
        c->bit_rate = 400000;
        c->width = vWidth;
        c->height = vHeight;
        c->time_base.num = 1;
        c->time_base.den = 10;
        c->gop_size = 12;
        c->pix_fmt = PIX_FMT_YUV420P;
        if (c->codec_id == CODEC_ID_MPEG2VIDEO)
        {
            c->max_b_frames = 2;
        }
        if (c->codec_id == CODEC_ID_MPEG1VIDEO)
        {
            c->mb_decision = 2;
        }
        if (!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
        {
            c->flags |= CODEC_FLAG_GLOBAL_HEADER;
        }
    }

    if (av_set_parameters(oc, NULL)<0)
    {
        return FALSE;
    }
    
    dump_format(oc, 0, videofile, 1);
    if (video_st)
    {
        AVCodecContext* c;
        AVCodec* codec;
        c = video_st->codec;
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec)
        {
            return FALSE;
        }
        if (avcodec_open(c, codec) < 0)
        {
            return FALSE;
        }
        if (!(oc->oformat->flags & AVFMT_RAWPICTURE))
        {
            video_outbuf_size = 200000;
            video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
        }
        picture = avcodec_alloc_frame();
        size = avpicture_get_size(c->pix_fmt, c->width, c->height);
        picture_buf = (uint8_t*)av_malloc(size);
        if (!picture_buf)
        {
            av_free(picture);
        }
        avpicture_fill((AVPicture*)picture, picture_buf, c->pix_fmt, c->width, c->height);
    }

    if (!(fmt->flags & AVFMT_NOFILE))
    {
        if (url_fopen(&oc->pb, videofile, URL_WRONLY) < 0)
        {
            return FALSE;
        }
    }
    av_write_header(oc);

    for (int i=0; i<count; i  )
    {
        if (savedlg)
        {
            savedlg->PostMessage(WM_COUNT, NULL, (LPARAM)i);
        }
    
        if (video_st)
        {
            video_pts = (double)(video_st->pts.val * video_st->time_base.num / video_st->time_base.den);
        }
        else
        {
            video_pts = 0.0;
        }
        if (!video_st/* || video_pts >= 5.0*/)
        {
            break;
        }
        AVCodecContext* c;
        c = video_st->codec;
        size = c->width * c->height;

        if (fread(picture_buf, 1, size*3/2, fin) < 0)
        {
            break;
        }
        
        picture->data[0] = picture_buf;  // 亮度
        picture->data[1] = picture_buf  size;  // 色度 
        picture->data[2] = picture_buf  size*5/4; // 色度 

        if (oc->oformat->flags & AVFMT_RAWPICTURE)
        {
            AVPacket pkt;
            av_init_packet(&pkt);
            pkt.flags |= PKT_FLAG_KEY;
            pkt.stream_index = video_st->index;
            pkt.data = (uint8_t*)picture;
            pkt.size = sizeof(AVPicture);
            ret = av_write_frame(oc, &pkt);
        }
        else
        {
            int out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
            if (out_size > 0)
            {
                AVPacket pkt;
                av_init_packet(&pkt);
                pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
                if (c->coded_frame->key_frame)
                {
                    pkt.flags |= PKT_FLAG_KEY;
                }
                pkt.stream_index = video_st->index;
                pkt.data = video_outbuf;
                pkt.size = out_size;
        
                ret = av_write_frame(oc, &pkt);
            }
        }
    }

    if (video_st)
    {
        avcodec_close(video_st->codec);

        av_free(picture);
        av_free(video_outbuf);

    }
    av_write_trailer(oc);
    for (int j=0; j<oc->nb_streams; j  )
    {
        av_freep(&oc->streams[j]->codec);
        av_freep(&oc->streams[j]);
    }
    if (!(fmt->flags & AVFMT_NOFILE))
    {
        url_fclose(oc->pb);
    }
    av_free(oc);
    fclose(fin);
    DeleteFile(YUVfile);
    //AfxMessageBox("视频已保存!");
    
    return TRUE;

}

复制代码

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多