想必搞音视频的朋友都知道ffmpeg,在这里我就不对它进行详细的介绍了。本文基于我们在Linux系统中安装部署ffmpeg的实际经验,给出了ffmpeg编译安装说明,并给出了实际的编程说明。
1.软件准备
1)SDL源码包
该软件主要实现播放需求,可以从http://www.libsdl.org 上下载SDL。SDL有SDL1.2及SDL2.0版本,我们使用的是SDL2.0版本(下载文件SDL2-2.0.5.tar.gz)。
2)yasm源码包
该软件在编译ffmpeg的时候会用到,可以从http://yasm.tortall.net/Download.html 上下载yasm-1.3.0.tar.gz。
3)ffmpeg源码包
可以从http://www.ffmpeg.org/download.html 上下载ffmpeg-3.2.4.tar.bz2。
2.编译安装
(1)编译安装SDL包
第一步,执行“tar zxvf SDL2-2.0.5.tar.gz”命令将文件解压到当前目录下。
第二步,进入SDL2-2.0.5目录执行“./configure –prefix=/usr/local/SDL”命令。
第三步,执行make命令。
第四步,执行make install命令。
第五步,设置环境变量,执行export PATH=”$PATH:/usr/local/SDL/bin:/usr/local/SDL/include:/usr/local/SDL/lib”。
(2)编译安装yasm包
第一步,执行“tar zxvf yasm-1.3.0.tar.gz ”命令将文件解压到当前目录下。
第二步,进入yasm-1.3.0目录执行“./configure –prefix=/usr/local/yasm”命令。
第三步,执行make命令。
第四步,执行make install命令。
第五步,设置环境变量,执行export PATH=”$PATH:/usr/local/yasm/bin”。
(3)编译安装ffmpeg包
第一步,执行“tar jxvf ffmpeg-3.2.4.tar.bz2 ”命令将文件解压到当前目录下。
第二步,进入ffmpeg-3.2.4目录执行“./configure –enable-static –enable-memalign-hack –prefix=/usr/local/ffmpeg”命令。
第三步,执行make命令。
第四步,执行make install命令。
3.安装结果说明
在/usr/local/ffmpeg目录下有bin、lib、include及share目录,其中bin目录下有ffmpeg、ffplay、ffprobe及ffserver 4个可执行文件。
4.应用编程说明
我们可通过调用ffmepg提供的函数接口来实现流媒体操作,此时需要用到安装目录(/usr/local/ffmpeg)下的include目录及lib目录。
makefile文件编写实例如下:
CC=gcc
CFLAGS=-I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -lavdevice -lavfilter -lavformat -lavcodec -ldl -lz -lswresample -lswscale -lavutil -lm -pthread
PROG=record_test
all:
$(CC) record_test.c -o $(PROG) $(CFLAGS)
clean:
rm $(PROG)
实例代码文件record_test.c内容如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
static AVFormatContext *i_fmt_ctx;
static AVStream *i_video_stream;
static AVFormatContext *o_fmt_ctx;
static AVStream *o_video_stream;
static int bStop = 0;
static pthread_t tid = NULL;
void *rtsp2mp4()
{
int i = 0;
avcodec_register_all();
av_register_all();
avformat_network_init();
/* should set to NULL so that avformat_open_input() allocate a new one */
i_fmt_ctx = NULL;
char rtspUrl[] = "rtsp://admin:123456@192.168.10.80/media/video1";
const char *filename = "1.mp4";
if (avformat_open_input(&i_fmt_ctx, rtspUrl, NULL, NULL)!=0)
{
fprintf(stderr, "could not open input file\n");
return (void*)-1;
}
if (avformat_find_stream_info(i_fmt_ctx, NULL)<0)
{
fprintf(stderr, "could not find stream info\n");
return (void*)-1;
}
//av_dump_format(i_fmt_ctx, 0, argv[1], 0);
/* find first video stream */
for (i=0; i<i_fmt_ctx->nb_streams; i++)
{
if (i_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
i_video_stream = i_fmt_ctx->streams[i];
break;
}
}
if (i_video_stream == NULL)
{
fprintf(stderr, "didn't find any video stream\n");
return (void*)-1;
}
avformat_alloc_output_context2(&o_fmt_ctx, NULL, NULL, filename);
/*
* since all input files are supposed to be identical (framerate, dimension, color format, ...)
* we can safely set output codec values from first input file
*/
o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);
{
AVCodecContext *c;
c = o_video_stream->codec;
c->bit_rate = 400000;
c->codec_id = i_video_stream->codec->codec_id;
c->codec_type = i_video_stream->codec->codec_type;
c->time_base.num = i_video_stream->time_base.num;
c->time_base.den = i_video_stream->time_base.den;
fprintf(stderr, "time_base.num = %d time_base.den = %d\n", c->time_base.num, c->time_base.den);
c->width = i_video_stream->codec->width;
c->height = i_video_stream->codec->height;
c->pix_fmt = i_video_stream->codec->pix_fmt;
printf("%d %d %d", c->width, c->height, c->pix_fmt);
c->flags = i_video_stream->codec->flags;
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
c->me_range = i_video_stream->codec->me_range;
c->max_qdiff = i_video_stream->codec->max_qdiff;
c->qmin = i_video_stream->codec->qmin;
c->qmax = i_video_stream->codec->qmax;
c->qcompress = i_video_stream->codec->qcompress;
}
avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
avformat_write_header(o_fmt_ctx, NULL);
int last_pts = 0;
int last_dts = 0;
int64_t pts, dts;
while (!bStop)
{
AVPacket i_pkt;
av_init_packet(&i_pkt);
i_pkt.size = 0;
i_pkt.data = NULL;
if (av_read_frame(i_fmt_ctx, &i_pkt) <0 )
break;
/*
* pts and dts should increase monotonically
* pts should be >= dts
*/
i_pkt.flags |= AV_PKT_FLAG_KEY;
pts = i_pkt.pts;
i_pkt.pts += last_pts;
dts = i_pkt.dts;
i_pkt.dts += last_dts;
i_pkt.stream_index = 0;
//printf("%lld %lld\n", i_pkt.pts, i_pkt.dts);
static int num = 1;
printf("frame %d\n", num++);
av_interleaved_write_frame(o_fmt_ctx, &i_pkt);
//av_free_packet(&i_pkt);
//av_init_packet(&i_pkt);
last_dts = dts;
last_pts = pts;
sleep(10);
}
avformat_close_input(&i_fmt_ctx);
av_write_trailer(o_fmt_ctx);
avcodec_close(o_fmt_ctx->streams[0]->codec);
av_freep(&o_fmt_ctx->streams[0]->codec);
av_freep(&o_fmt_ctx->streams[0]);
avio_close(o_fmt_ctx->pb);
av_free(o_fmt_ctx);
return (void*)0;
}
int main(int argc, char **argv)
{
//ffplay();
bStop = 0;
int err = 0;
err = pthread_create( &tid, NULL, rtsp2mp4, NULL );
if ( err != 0 )
{
printf("failed create thread: %s\n",strerror(err));
return -1;
}
printf("press any key to stop record!\n");
getchar();
bStop = 1;
printf("press any key to quit!\n");
getchar();
return 0;
}