1、视频编码
环境配了半天(下午到晚上)。具体怎么配好我也不记得了,,就一通乱下
下载x264后要重新编译ffmpeg ./configure --enable-shared --enable-libx264 --enable-gpl --enable-pthreads
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){
int ret = -1;
ret = avcodec_send_frame(ctx, frame);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder!\n");
goto _END;
}
while( ret >= 0){
ret = avcodec_receive_packet(ctx, pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
return 0;
} else if( ret < 0) {
return -1; //退出tkyc
}
fwrite(pkt->data, 1, pkt->size, out);
av_packet_unref(pkt);
}
_END:
return 0;
}
int main(int argc, char* argv[]){
int ret = -1;
FILE *f = NULL;
char *dst = NULL;
char *codecName = NULL;
const AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVFrame *frame = NULL;
AVPacket *pkt = NULL;
av_log_set_level(AV_LOG_DEBUG);
//1. 输入参数
if(argc < 3){
av_log(NULL, AV_LOG_ERROR, "arguments must be more than 3\n");
goto _ERROR;
}
dst = argv[1];
codecName = argv[2];
//2. 查找编码器
codec = avcodec_find_encoder_by_name(codecName);
if(!codec){
av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
goto _ERROR;
}
//3. 创建编码器上下文
ctx = avcodec_alloc_context3(codec);
if(!ctx){
av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
goto _ERROR;
}
//4. 设置编码器参数
ctx->width = 640;
ctx->height = 480;
ctx->bit_rate = 500000;
ctx->time_base = (AVRational){1, 25};
ctx->framerate = (AVRational){25, 1};
ctx->gop_size = 10;
ctx->max_b_frames = 1;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if(codec->id == AV_CODEC_ID_H264){
av_opt_set(ctx->priv_data, "preset", "slow", 0);
}
//5. 编码器与编码器上下文绑定到一起
ret = avcodec_open2(ctx, codec , NULL);
if(ret < 0) {
av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
goto _ERROR;
}
//6. 创建输出文件
f = fopen(dst, "wb");
if(!f){
av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
goto _ERROR;
}
//7. 创建AVFrame
frame = av_frame_alloc();
if(!frame){
av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
goto _ERROR;
}
frame->width = ctx->width;
frame->height = ctx->height;
frame->format = ctx->pix_fmt;
ret = av_frame_get_buffer(frame, 0);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
goto _ERROR;
}
//8. 创建AVPacket
pkt = av_packet_alloc();
if(!pkt){
av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
goto _ERROR;
}
//9. 生成视频内容
for(int i=0; i<25; i++){
ret = av_frame_make_writable(frame);
if(ret < 0) {
break;
}
//Y分量
for(int y = 0; y < ctx->height; y++){
for(int x=0; x < ctx->width; x++){
frame->data[0][y*frame->linesize[0]+x] = x + y + i * 3;
}
}
//UV分量
for(int y=0; y< ctx->height/2; y++){
for(int x=0; x < ctx->width/2; x++){
frame->data[1][y * frame->linesize[1] + x ] = 128 + y + i * 2;
frame->data[2][y * frame->linesize[2] + x ] = 64 + x + i * 4;
}
}
frame->pts = i;
//10. 编码
ret = encode(ctx, frame, pkt, f);
if(ret == -1){
goto _ERROR;
}
}
//10. 编码
encode(ctx, NULL, pkt, f);
_ERROR:
//ctx
if(ctx){
avcodec_free_context(&ctx);
}
//avframe
if(frame){
av_frame_free(&frame);
}
//avpacket
if(pkt){
av_packet_free(&pkt);
}
//dst
if(f){
fclose(f);
}
return 0;
}
2、音频编码
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavutil/samplefmt.h>
#include <libavcodec/avcodec.h>
static int select_best_sample_rate(const AVCodec *codec){
const int *p;
int best_samplerate = 0;
if(!codec->supported_samplerates){
return 44100;
}
p = codec->supported_samplerates;
while(*p){
if(!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate)){
best_samplerate = *p;
}
p++;
}
return best_samplerate;
}
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt){
const enum AVSampleFormat *p = codec->sample_fmts;
while(*p != AV_SAMPLE_FMT_NONE){
if( *p == sample_fmt) {
return 1;
}
p++;
}
return 0;
}
static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){
int ret = -1;
ret = avcodec_send_frame(ctx, frame);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder: %s!\n", av_err2str(ret));
goto _END;
}
while( ret >= 0){
ret = avcodec_receive_packet(ctx, pkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
return 0;
} else if( ret < 0) {
return -1; //退出tkyc
}
av_log(NULL, AV_LOG_DEBUG, "ptk.size:%d\n", pkt->size);
fwrite(pkt->data, 1, pkt->size, out);
av_packet_unref(pkt);
}
_END:
return 0;
}
int main(int argc, char* argv[]){
int ret = -1;
FILE *f = NULL;
char *dst = NULL;
char *codecName = NULL;
const AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVFrame *frame = NULL;
AVPacket *pkt = NULL;
uint16_t *samples = NULL;
av_log_set_level(AV_LOG_DEBUG);
//1. 输入参数
if(argc < 2){
av_log(NULL, AV_LOG_ERROR, "arguments must be more than 2\n");
goto _ERROR;
}
dst = argv[1];
//codecName = argv[2];
//2. 查找编码器
//codec = avcodec_find_encoder_by_name(codecName);
codec = avcodec_find_encoder_by_name("libfdk_aac");
//codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if(!codec){
av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s", codecName);
goto _ERROR;
}
//3. 创建编码器上下文
ctx = avcodec_alloc_context3(codec);
if(!ctx){
av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n");
goto _ERROR;
}
//4. 设置编码器参数
ctx->bit_rate = 64000;
ctx->sample_fmt = AV_SAMPLE_FMT_S16;//AV_SAMPLE_FMT_FLTP
if(!check_sample_fmt(codec, ctx->sample_fmt)){
av_log(NULL, AV_LOG_ERROR, "Encoder does not support sample format!\n");
goto _ERROR;
}
ctx->sample_rate = select_best_sample_rate(codec);
av_channel_layout_copy(&ctx->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO
//5. 编码器与编码器上下文绑定到一起
ret = avcodec_open2(ctx, codec , NULL);
if(ret < 0) {
av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s \n", av_err2str(ret));
goto _ERROR;
}
//6. 创建输出文件
f = fopen(dst, "wb");
if(!f){
av_log(NULL, AV_LOG_ERROR, "Don't open file:%s", dst);
goto _ERROR;
}
//7. 创建AVFrame
frame = av_frame_alloc();
if(!frame){
av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
goto _ERROR;
}
frame->nb_samples = ctx->frame_size;
frame->format = AV_SAMPLE_FMT_S16; //AV_SAMPLE_FMT_FLTP
av_channel_layout_copy(&frame->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); //AV_CHANNEL_LAYOUT_MONO
frame->sample_rate = ctx->sample_rate;
ret = av_frame_get_buffer(frame, 0);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame \n");
goto _ERROR;
}
//8. 创建AVPacket
pkt = av_packet_alloc();
if(!pkt){
av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
goto _ERROR;
}
//9. 生成音频内容
float t = 0;
float tincr = 4*M_PI*440/ctx->sample_rate;
for(int i=0; i < 200; i++){
ret = av_frame_make_writable(frame);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate space!\n");
goto _ERROR;
}
samples = (uint16_t*)frame->data[0]; //FLTP 32 (uint32_t*)
for(int j=0; j < ctx->frame_size; j++){
samples[2*j] = (int)((t)*10000); //4
for(int k=1; k < ctx->ch_layout.nb_channels; k++){
samples[2*j + k] = samples[2*j]; //4
}
t += tincr;
}
encode(ctx, frame, pkt, f);
}
//10. 编码
encode(ctx, NULL, pkt, f);
_ERROR:
//ctx
if(ctx){
avcodec_free_context(&ctx);
}
//avframe
if(frame){
av_frame_free(&frame);
}
//avpacket
if(pkt){
av_packet_free(&pkt);
}
//dst
if(f){
fclose(f);
}
return 0;
}
3、视频抽取图片
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#define WORD uint16_t
#define DWORD uint32_t
#define LONG int32_t
#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
void saveBMP(struct SwsContext *img_convert_ctx, AVFrame *frame, int w, int h, char *filename)
{
//1 先进行转换, YUV420=>RGB24:
// int w = img_convert_ctx->frame_dst->width;
// int h = img_convert_ctx->frame_dst->height;
int data_size = w * h * 3;
AVFrame *pFrameRGB = av_frame_alloc();
//avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, w, h);
pFrameRGB->width = w;
pFrameRGB->height = h;
pFrameRGB->format = AV_PIX_FMT_BGR24;
av_frame_get_buffer(pFrameRGB, 0);
sws_scale(img_convert_ctx,
(const uint8_t* const *)frame->data,
frame->linesize,
0, frame->height, pFrameRGB->data, pFrameRGB->linesize);
//2 构造 BITMAPINFOHEADER
BITMAPINFOHEADER header;
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = w;
header.biHeight = h*(-1);
header.biBitCount = 24;
header.biCompression = 0;
header.biSizeImage = 0;
header.biClrImportant = 0;
header.biClrUsed = 0;
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biPlanes = 1;
//3 构造文件头
BITMAPFILEHEADER bmpFileHeader = {0,};
//HANDLE hFile = NULL;
DWORD dwTotalWriten = 0;
DWORD dwWriten;
bmpFileHeader.bfType = 0x4d42; //'BM';
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ data_size;
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
FILE* pf = fopen(filename, "wb");
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
fwrite(&header, sizeof(BITMAPINFOHEADER), 1, pf);
fwrite(pFrameRGB->data[0], 1, data_size, pf);
fclose(pf);
//释放资源
//av_free(buffer);
av_freep(&pFrameRGB[0]);
av_free(pFrameRGB);
}
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
char *filename)
{
FILE *f;
int i;
f = fopen(filename,"w");
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
}
static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
struct SwsContext *img_convert_ctx, AVFrame *frame, AVPacket *pkt)
{
int ret = -1;
char buf[1024];
ret = avcodec_send_packet(avctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error while decoding frame, %s(%d)\n", av_err2str(ret), ret);
return ret;
}
while (ret >= 0) {
fflush(stdout);
ret = avcodec_receive_frame(avctx, frame);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
return 0;
}else if( ret < 0){
return -1;
}
/* the picture is allocated by the decoder, no need to free it */
snprintf(buf, sizeof(buf), "%s-%d.bmp", outfilename, avctx->frame_number);
/*pgm_save(frame->data[0], frame->linesize[0],
frame->width, frame->height, buf);*/
saveBMP(img_convert_ctx, frame, 160, 120, buf);
}
return 0;
}
int main(int argc, char **argv)
{
int ret;
int idx;
const char *filename, *outfilename;
AVFormatContext *fmt_ctx = NULL;
const AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVStream *inStream = NULL;
AVFrame *frame = NULL;
AVPacket avpkt;
struct SwsContext *img_convert_ctx;
if (argc <= 2) {
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(0);
}
filename = argv[1];
outfilename = argv[2];
/* open input file, and allocate format context */
if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", filename);
exit(1);
}
/* retrieve stream information */
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
/* dump input information to stderr */
//av_dump_format(fmt_ctx, 0, filename, 0);
//av_init_packet(&avpkt);
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
//memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
//
idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (idx < 0) {
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO), filename);
return idx;
}
inStream = fmt_ctx->streams[idx];
/* find decoder for the stream */
codec = avcodec_find_decoder(inStream->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "Failed to find %s codec\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
return AVERROR(EINVAL);
}
ctx = avcodec_alloc_context3(NULL);
if (!ctx) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
/* Copy codec parameters from input stream to output codec context */
if ((ret = avcodec_parameters_to_context(ctx, inStream->codecpar)) < 0) {
fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",
av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
return ret;
}
/* open it */
if (avcodec_open2(ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
img_convert_ctx = sws_getContext(ctx->width, ctx->height,
ctx->pix_fmt,
160, 120,
AV_PIX_FMT_BGR24,
SWS_BICUBIC, NULL, NULL, NULL);
if (img_convert_ctx == NULL)
{
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
while (av_read_frame(fmt_ctx, &avpkt) >= 0) {
if(avpkt.stream_index == idx){
if (decode_write_frame(outfilename, ctx, img_convert_ctx, frame, &avpkt) < 0)
exit(1);
}
av_packet_unref(&avpkt);
}
decode_write_frame(outfilename, ctx, img_convert_ctx, frame, NULL);
avformat_close_input(&fmt_ctx);
sws_freeContext(img_convert_ctx);
avcodec_free_context(&ctx);
av_frame_free(&frame);
return 0;
}