Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————H264压缩视频

H264视频压缩主要步骤

  1. 压缩前的一些初始化
  2. 压缩帧再写入文件
  3. 压缩完成后资源的一些清理
/* encode.c */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <x264.h>
#include <pthread.h>
#include "config.h"
#include "encode.h"
#include "queue.h"

#define CONFIG_CSP X264_CSP_I422

typedef enum {
    ENCODE_STATE_STOP,
    ENCODE_STATE_START
} eEncodeState;

struct {
    x264_nal_t* pNals;
    x264_t* pHandle;
    x264_picture_t* pPicIn;
    x264_param_t* pParam;
    eEncodeState State;
    pthread_t EncodeThreadId;
    FILE* pFile;
    sQueue QueuePrivateData;
} sEncodePrivateData;

static int H264FrameEncodeBegin(uint32_t Width, uint32_t Height)
{
    QueueInit(&sEncodePrivateData.QueuePrivateData);
    sEncodePrivateData.pPicIn = (x264_picture_t*)malloc(sizeof(x264_picture_t));
    sEncodePrivateData.pParam = (x264_param_t*)malloc(sizeof(x264_param_t));

    x264_param_default(sEncodePrivateData.pParam);
    x264_param_default_preset(sEncodePrivateData.pParam, "fast" , "zerolatency" );

    /* 设置参数 */
    sEncodePrivateData.pParam->i_csp = CONFIG_CSP;
    sEncodePrivateData.pParam->i_width = Width;
    sEncodePrivateData.pParam->i_height = Height;
    sEncodePrivateData.pParam->i_fps_num = CONFIG_CAPTURE_FPS;
    sEncodePrivateData.pParam->i_fps_den = 1;

    sEncodePrivateData.pParam->i_threads  = X264_SYNC_LOOKAHEAD_AUTO;
    sEncodePrivateData.pParam->i_keyint_max = 10;

    sEncodePrivateData.pParam->rc.i_bitrate = CONFIG_ENCODE_BITRATE;
    sEncodePrivateData.pParam->rc.i_rc_method = X264_RC_ABR;

    x264_param_apply_profile(sEncodePrivateData.pParam, "high422");

    sEncodePrivateData.pHandle = x264_encoder_open(sEncodePrivateData.pParam);

    x264_picture_alloc(sEncodePrivateData.pPicIn, CONFIG_CSP,
        sEncodePrivateData.pParam->i_width, sEncodePrivateData.pParam->i_height);

    return 0;
}

static int H264FrameEncodeEnd(void)
{
    printf("Encode end, now clear resource\n");
    if (sEncodePrivateData.pHandle) {
        x264_encoder_close(sEncodePrivateData.pHandle);
    }

    if (sEncodePrivateData.pPicIn) {
        x264_picture_clean(sEncodePrivateData.pPicIn);
        free(sEncodePrivateData.pPicIn);
        sEncodePrivateData.pPicIn = NULL;
    }

    if (sEncodePrivateData.pParam) {
        free(sEncodePrivateData.pParam);
        sEncodePrivateData.pParam = NULL;
    }
    if(sEncodePrivateData.pFile) {
        fclose(sEncodePrivateData.pFile);
        sEncodePrivateData.pFile = NULL;
    }

    return 0;
}

static int H264FrameEncode(const uint8_t* pData, uint32_t Width, uint32_t Height, uint32_t Length)
{
    x264_picture_t* pPicOut = (x264_picture_t*)malloc(sizeof(x264_picture_t));
    if(!pPicOut) {
        perror("Malloc failed");
        return -1;
    }
    x264_picture_init(pPicOut);

    int IndexY, IndexU, IndexV;
    int YuyvLength = Width * Height * 2 - 4;
    int NalCnt = 0;
    int Result = 0;
    static long int pts = 0;
    // uint8_t* pOut = pDataOut;
    uint8_t* pY = sEncodePrivateData.pPicIn->img.plane[0];
    uint8_t* pU = sEncodePrivateData.pPicIn->img.plane[1];
    uint8_t* pV = sEncodePrivateData.pPicIn->img.plane[2];

    // if(YuyvLength != Length) {
    //  printf("Param invalid, Length not match\n");
    //  return -1;
    // }

    IndexY = 0;
    IndexU = 0;
    IndexV = 0;

    for(int i = 0; i < YuyvLength; i += 4) {
            *(pY + (IndexY++)) = *(pData + i);
            *(pU + (IndexU++)) = *(pData + i + 1);
            *(pY + (IndexY++)) = *(pData + i + 2);
            *(pV + (IndexV++)) = *(pData + i + 3);
    }

    sEncodePrivateData.pPicIn->i_type = X264_TYPE_AUTO;

    sEncodePrivateData.pPicIn->i_pts = pts++;

    if (x264_encoder_encode(sEncodePrivateData.pHandle, &(sEncodePrivateData.pNals), &NalCnt, sEncodePrivateData.pPicIn, pPicOut) < 0) {
        free(pPicOut);
        return -1;
    }
    for (int i = 0; i < NalCnt; i++) {
        // memcpy(pOut, sEncodePrivateData.pNals[i].p_payload, sEncodePrivateData.pNals[i].i_payload);
        // pOut += sEncodePrivateData.pNals[i].i_payload;
        fwrite(sEncodePrivateData.pNals[i].p_payload, 1, sEncodePrivateData.pNals[i].i_payload, sEncodePrivateData.pFile);
        Result += sEncodePrivateData.pNals[i].i_payload;
    }

    free(pPicOut);

    return Result;
}

static void* H264EncodeThread(void* pParam)
{
    int Ret = -1;
    while(sEncodePrivateData.State == ENCODE_STATE_START) {
        sQueueData QueueData;
        Ret = QueuePopData(&sEncodePrivateData.QueuePrivateData, &QueueData);
        if(Ret) {
            continue;
        }
        H264FrameEncode(QueueData.pData,
                CONFIG_CAPTURE_WIDTH, CONFIG_CAPTURE_HEIGHT,
                QueueData.Length);
        QueueCallback(&QueueData);
    }
    H264FrameEncodeEnd();
    return NULL;
}

int EncodeStart(const char* pFilename)
{
    H264FrameEncodeBegin(CONFIG_CAPTURE_WIDTH, CONFIG_CAPTURE_HEIGHT);

    if(sEncodePrivateData.State) {
        printf("Encode thread already start\n");
        return -1;
    }
    sEncodePrivateData.State = ENCODE_STATE_START;

    sEncodePrivateData.pFile = fopen(pFilename, "w+");
    if(!sEncodePrivateData.pFile) {
        perror("Create h264 file failed");
        return -1;
    }

    pthread_create(&sEncodePrivateData.EncodeThreadId, NULL, H264EncodeThread, (void *)NULL);

    return 0;
}

int EncodeStop(void)
{
    sEncodePrivateData.State = ENCODE_STATE_STOP;
    pthread_join(sEncodePrivateData.EncodeThreadId, NULL);
    printf("Encode thread stop\n");
    return 0;
}
/* encode.h */
#ifndef ENCODE_H
#define ENCODE_H

int EncodeStart(const char* pFilename);

int EncodeStop(void);

#endif

原文地址:https://www.cnblogs.com/rootming/p/10853982.html

时间: 2024-08-30 01:12:15

Linux下V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————H264压缩视频的相关文章

V4L2捕捉画面+H264压缩视频+帧缓冲显示视频————帧缓冲显示视频

帧缓冲显示主要步骤 打开设备文件, 比如/dev/fb0 获取framebuffer的一些信息, 比如分辨率 设置参数 映射framebuffer内存到用户空间 写入要显示的画面 /* display.c */ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <unistd

摄像头v4l2编写,实现视频在帧缓冲显示

申明:该文档只是记录我的编写和理解过程,代码部分参考了较多的文章,如有意见请联系我删除,谢谢. 目标: 使用v4l2提供API,完成摄像头视频采集,并使用帧缓存显示. 准备工作: USB摄像头1个 编译环境(我用的是PC+Ubuntu14.04) 了解大概情况,查看如下网址,基本情况应该没问题了:http://baike.baidu.com/item/V4L2?sefr=enterbtn 框架理解: 关键点理解: 摄像头采集的循环buf 必须使用循环buf,否则摄像头采集图像显示不会连续. 摄像

C语言高级应用---操作linux下V4L2摄像头应用程序

我们都知道,想要驱动linux下的摄像头,其实很简单,照着V4L2的手册一步步来写,很快就可以写出来,但是在写之前我们要注意改变系统的一些配置,使系统支持framebuffer,在dev下产生fb0这样的节点,这样我们才能在linux系统上操作Camera摄像头,framebuffer在之前的博文已经有说过了,这里就不再提了. 有需要了解framebuffer的那么请点击:http://baike.baidu.com/view/3351639.htm 最重要的,我们需要改一个脚本,在/dev/g

Linux下追踪函数调用,打印栈帧

事情的起因是这样的,之前同事的代码有一个内存池出现了没有回收的情况.也就是是Pop出来的对象没有Push回去,情况很难复现,所以在Pop里的打印日志,跟踪是谁调用了它,我想在GDB调试里可以追踪调用的栈帧,那也一定有方法实现.首先上网搜索了一下,并没有结果!还好代码量不是很多,只能用最笨的方法,在每个调用Pop的地方,传参,把调用的文件,行号作为字符串传进去,在日志里打印!忙活完了,总感觉一定是有方法可以实现查看调用栈帧的,于是在QQ群里的问了下,果然有这方面经验的同学给出了答案! 主要是通过b

解决linux下oracle进入sqlplus环境中后退键显示^H、上下键无效与ctrl+l无法清屏等问题【weber出品必属精品】

习惯linux中上下键回退历史输入的人们肯定也希望sqlplus中也能实现相同的效果,可是不幸的是,sqlplus中不提供诸多方便的快捷键,这个时候我们就需要另外安装一个插件来实现这个想法. 这个插件叫做: rlwrap 进入rlwrap的官网去下载这个插件:http://utopia.knoware.nl/~hlub/uck/rlwrap/ 下载完后进行解压操作tar -zxf rlwrap-0.41.tar.gz 解压后得到rlwrap这个文件夹,进入其中. 给configure赋权 # c

shell脚本编程《linux下kvm虚拟机的创建、开启、显示、停止、重置》

Shell脚本编程--案例一 编程要求: 1.创建vm-ctl脚本,在/bin/下 2.实现功能:创建虚拟机.创建虚拟机快照.开启虚拟机.显示虚拟机.停止虚拟机.重置虚拟机. 脚本实现预期结果: sh vm-ctl create|nodecreate|start|view|stop|reset vmname 实现脚本如下: #!/bin/bash case "$1" in create)            ##创建虚拟机 echo create vm $2 ... virt-ins

linux下使用date、hwclock和clock命令显示和设定时钟

linux将时钟分为系统时钟(System Clock)和硬件时钟(Real Time Clock )两种.系统时间指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的那个主板硬件时钟,这个时钟可以在BIOS的“Standard BIOS Feture”项中进行设置.当linux启动时,硬件时钟会去读取系统时钟的设置,然后系统时钟就会独立于硬件运作,因此系统时钟和硬件时钟可以采用异步方式,即系统时间和硬件时间可以不同.从linux启动过程来看,系统时钟和硬件时钟不会发生冲突,

linux 下 python 调用 mplayer 解析歌词同步播放显示

加载同目录同名歌词同步显示 #!/usr/bin/python # -*- coding: utf-8 -*- import sys, os, time, subprocess, re, chardet def load_lrc(lrc_file):     try:         lrc_contains = open(lrc_file, 'rb').read()         encoding = chardet.detect(lrc_contains)['encoding']     

帧缓冲子系统框架

1  Linux帧缓冲子系统 帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,它把显示设备描述成一个缓冲区,允许应用程序在图形模式下直接对显示显示缓冲区进行读写操作. 帧缓冲是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容.通过不断的向帧缓冲写入数据,显示控制器就自动的从帧缓冲中读取数据并显示出来.帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示设备,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0~fb31,帧缓