音视频开发---FFmpeg+SDL本地摄像头直播

 

    继上一篇ffmpeg录像并保存为mp4之后, 这一篇介绍摄像头本地直播,基于FFmpeg+SDL2实现, 代码中关键部分都有注释,这里不再叙述,详细代码如下:


/**
	摄像头SDL直播
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"

#include <SDL2/SDL.h>

#define DST_PIX_FMT AV_PIX_FMT_YUV420P

const char* input_name= "video4linux2";
const char* file_name = "/dev/video0";
int screen_w=   640;
int screen_h =  480;
static SDL_Window * win = NULL;
static SDL_Renderer * renderer = NULL;
static SDL_Texture * texture = NULL;

int init_sdl(int w_width, int w_height)
{

    int ret;
    if( (ret = SDL_Init(SDL_INIT_VIDEO))){
        printf("SDL_Init failed\n");
        return -1;
    }
    win = SDL_CreateWindow("sdl player", SDL_WINDOWPOS_UNDEFINED, 
        SDL_WINDOWPOS_UNDEFINED,
        w_width, w_height,
        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if(!win){
        printf("SDL_CreateWindow failed\n");
        return -1;
    }
    if( (renderer = SDL_CreateRenderer(win,-1, 0)) == NULL){
        printf("SDL_CreateRenderer failed\n");
        return -1;
    }
    
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV,
        SDL_TEXTUREACCESS_STREAMING, w_width, w_height);
    return 0;
}


int sdl_show_yuv(AVFrame *pFrame)
{
    SDL_Rect rect;
    if( pFrame == NULL)
        return -1;
    SDL_UpdateYUVTexture(texture,NULL,
                             pFrame->data[0], pFrame->linesize[0],
                             pFrame->data[1], pFrame->linesize[1],
                             pFrame->data[2], pFrame->linesize[2]);
    rect.x = 0;
    rect.y = 0;
    rect.w = screen_w;
    rect.h = screen_h;
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texture, NULL, &rect);
    SDL_RenderPresent(renderer);
    return 0;
}

int main(int argc, char * argv[])
{    

    AVFormatContext *pInFmtContext = NULL;    
    AVInputFormat *inputFmt;
    AVStream *in_stream;
    AVCodecContext *pInCodecCtx;
    AVCodec *pInCodec;
    AVPacket *in_packet;
    AVFrame *pInFrame;

    AVFrame *pOutFrame;
        
    struct SwsContext * img_convert_ctx;
    SDL_Event event;

	int picture_size = 0;
    int ret;
    int videoindex = -1;
    int i;
    int got_picture = 0;
    
	int count = 125 * 10;
    int framecnt = 1;
    int stream_index =0;
    unsigned char * out_buffer = NULL;    
    int start_time = 0, end_time = 0;
    int quit_flag = 0;
    av_register_all();
    avdevice_register_all();

    pInFmtContext = avformat_alloc_context();
    
    //解封装,查找video4linux2的视频流输入格式
    if( (inputFmt = av_find_input_format (input_name)) == NULL){
		printf("av_find_input_format failed\n");
		return -1;
	}
    
    // Open an input stream and read the header, if pInFmtContext is NULL, avformat_open_input will malloc the memory.
    if (avformat_open_input ( &pInFmtContext, file_name, inputFmt, NULL) < 0){
        printf("avformat_open_input failed\n");         
		return -1;    
    }
    //print 
	av_dump_format(pInFmtContext, 0, file_name, 0); 

  	if( avformat_find_stream_info(pInFmtContext, NULL) < 0){
		printf("avformat_find_stream_info failed\n");
		return -1;
	}

	for(i=0;i<pInFmtContext->nb_streams;i++){
		if( pInFmtContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
			videoindex = i;
			break;
		}
	}
	if( videoindex == -1){
		printf("couldn't find a video stream\n");
		return -1;
	}
    in_stream = pInFmtContext->streams[videoindex];
    
	pInCodecCtx = in_stream->codec;
    screen_w = pInCodecCtx->width;
    screen_h = pInCodecCtx->height;
    init_sdl(screen_w, screen_h);
    
    //Find a registered decoder with a matching codec ID.
	pInCodec = avcodec_find_decoder(pInCodecCtx->codec_id);
    //Initialize the AVCodecContext to use the given AVCodec.,打开并初始化解码器
	if( avcodec_open2( pInCodecCtx, pInCodec,NULL) < 0){
		printf("avcodec_open2 failed\n");
		return -1;
	}

	pInFrame = av_frame_alloc();
    pOutFrame = av_frame_alloc();
    picture_size = av_image_get_buffer_size(DST_PIX_FMT, screen_w, screen_h, 1);
    out_buffer = (unsigned char *)av_malloc(picture_size);
    if( out_buffer == NULL){
        printf("malloc failed\n");
        return -1;
    }
    ret=av_image_fill_arrays((AVPicture *)pOutFrame->data, (AVPicture *)pOutFrame->linesize,
                                    out_buffer, DST_PIX_FMT, screen_w, screen_h, 1);

    in_packet = av_packet_alloc(); // in_packet = (AVPacket *)av_malloc(sizeof(AVPacket));  

    
	img_convert_ctx = sws_getContext( pInCodecCtx->width, pInCodecCtx->height, pInCodecCtx->pix_fmt,
		screen_w, screen_h, DST_PIX_FMT, SWS_BICUBIC, NULL, NULL, NULL);

 
    start_time = time(NULL);
    printf(" start time:%d\n", start_time);
    while(count-- &&  quit_flag == 0){
        if( av_read_frame( pInFmtContext, in_packet) >= 0){
            if( in_packet->stream_index == videoindex){
                if( (ret = avcodec_decode_video2(pInCodecCtx, pInFrame, &got_picture, in_packet)) < 0){
                    printf("avcodec_decode_video2 failed\n");
                    return -1;
                }
     
                if( got_picture == 1){
                    sws_scale( img_convert_ctx, (const uint8_t * const)pInFrame->data, pInFrame->linesize, 0, screen_h, pOutFrame->data, pOutFrame->linesize);
                    
                    // show with sdl
                    sdl_show_yuv(pOutFrame);
                                    
                }else{
                    printf("no.....\n");
                }
            }
        }else{
            printf("av_read_frame failed\n");
        }
        av_packet_unref(in_packet);

        SDL_PollEvent(&event);
        switch(event.type){
        case SDL_QUIT:
            quit_flag = 1;
            printf("stop.....\n");
            break;
        default:
            break;
        }

        
    }
	end_time  = time(NULL);
    printf("   end time:%d,%d\n", end_time, end_time - start_time);

    sws_freeContext( img_convert_ctx);

    avcodec_close(pInCodecCtx);
    
    av_frame_free(&pInFrame);
    av_frame_free(&pOutFrame);
    
    av_packet_free(&in_packet);
	
    avformat_close_input(&pInFmtContext);
    avformat_free_context(pInFmtContext);
	return 0;
}

编译:

gcc main.c  -I/usr/local/include -lavformat  -lavdevice -lavcodec -lavutil -lswscale -lSDL2

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值