网上根本没这方面的代码,要不就是opencv的,要不就是保存yuv的,或者mp4/avi的,不多说了,直接上代码,懒 :)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <Windows.h>
#include <thread>
#include <mutex>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include "libavfilter/avfilter.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/avutil.h"
#include "libavutil/pixfmt.h"
#include "libavutil/error.h"
#include "libavutil/imgutils.h"
}
using namespace std;
static void encode(AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt,
FILE* outfile)
{
int ret;
/* send the frame to the encoder */
if (frame)
printf("Send frame %3", frame->pts);
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0)
{
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0)
{
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
{
fprintf(stderr, "Error during encoding\n");
exit(1);
}
printf("Write packet %d size=%d \n", pkt->size, pkt->pts);
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
}
int main()
{
avdevice_register_all();
AVFormatContext* camFmtCtx = avformat_alloc_context();
AVDictionary* options = NULL;
//av_dict_set(&options, "list_devices", "true", 0);
//av_dict_set_int(&options, "rtbufsize", 18432000, 0);
AVInputFormat* iformat = av_find_input_format("dshow");
puts("Device Option Info======");
int ret = avformat_open_input(&camFmtCtx, "video=Vimicro USB 2.0 PC Camera (Venus)", iformat, &options);
if (ret != 0)
{
av_dict_free(&options);
return -1;
}
//查找输入流
ret = avformat_find_stream_info(camFmtCtx, NULL);
if (ret < 0)
{
cout << "无法获取流的信息" << endl;
return -1;
}
int videoindex = -1;
for (int i = 0; i < camFmtCtx->nb_streams; i++)
{
if (camFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
break;
}
}
//查找摄像头可用解码器
AVCodecContext* camDecodeCtx = camFmtCtx->streams[videoindex]->codec;
AVCodecID codecID = camFmtCtx->streams[videoindex]->codecpar->codec_id;
// cout << "codecID = " << codecID << endl;
AVCodec* codec = avcodec_find_decoder(codecID);
if (codec == NULL)
{
cout << "没有解码器" << endl;
return -1;
}
ret = avcodec_open2(camDecodeCtx, codec,NULL);
if (ret < 0)
{
cout << "avodec_open2 error" << endl;
return -1;
}
cout << "解码器打开成功" << endl;
//H264编码器,encode函数使用
AVCodecID encodeID = AV_CODEC_ID_H264;
AVCodec* encodec = avcodec_find_encoder(encodeID);
//avcodec_find_encoder_by_name();
if (!encodec)
{
cout << "encodec == NULL" << endl;
}
AVCodecContext* encodeCtx = avcodec_alloc_context3(encodec);
if (!encodeCtx)
{
cout << "enc == NULL" << endl;
}
encodeCtx->bit_rate = 400000;
encodeCtx->width = camDecodeCtx->width;
encodeCtx->height = camDecodeCtx->height;
encodeCtx->time_base = {1, 25};
encodeCtx->framerate = {25, 1};
encodeCtx->gop_size = 10;
encodeCtx->max_b_frames = 1;
encodeCtx->pix_fmt = AV_PIX_FMT_YUV420P;
//加载预设
av_opt_set(encodeCtx->priv_data, "preset", "slow", 0);
av_opt_set(encodeCtx->priv_data, "tune", "zerolatency", 0);
ret = avcodec_open2(encodeCtx, encodec,NULL);
if (ret < 0)
{
cout << "encodec open error" << endl;
exit(-1);
}
FILE* fp = nullptr;
fopen_s(&fp, "1.h264", "wb");
AVPacket* packetIn = av_packet_alloc();
AVPacket* packetOut = av_packet_alloc();
AVFrame* pFrameOut = av_frame_alloc();
int got_picture;
struct SwsContext* img_convert_ctx = sws_getContext(camDecodeCtx->width, camDecodeCtx->height,
camDecodeCtx->pix_fmt, camDecodeCtx->width,
camDecodeCtx->height, AV_PIX_FMT_YUV420P,
/*SWS_FAST_BILINEAR*/SWS_BICUBIC, NULL, NULL, NULL);
unsigned char* out_buffer = (unsigned char*)av_malloc(
av_image_get_buffer_size(AV_PIX_FMT_YUV420P, camDecodeCtx->width, camDecodeCtx->height, 16));
for (int i = 0; i < 250; i++)
{
ret = av_read_frame(camFmtCtx, packetIn); //摄像头取到packet,要转为pFrameYUV的yuv格式
if (ret >= 0 && packetIn->stream_index == videoindex)
{
AVFrame* pFrameYUV = av_frame_alloc();
pFrameYUV->format = AV_PIX_FMT_YUV420P;
pFrameYUV->width = camDecodeCtx->width;
pFrameYUV->height = camDecodeCtx->height;
avpicture_fill((AVPicture*)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, camDecodeCtx->width,
camDecodeCtx->height);
avcodec_decode_video2(camDecodeCtx, pFrameOut, &got_picture, packetIn);
if (got_picture)
{
sws_scale(img_convert_ctx, (const unsigned char* const*)pFrameOut->data, pFrameOut->linesize, 0,
camDecodeCtx->height,
pFrameYUV->data, pFrameYUV->linesize);
}
unsigned int untime = GetTickCount();
pFrameYUV->pts = untime;
encode(encodeCtx, pFrameYUV, packetOut, fp); //编码yuv
av_free(pFrameYUV);
}
}
av_free(pFrameOut);
av_packet_free(&packetIn);
av_packet_free(&packetOut);
sws_freeContext(img_convert_ctx);
avcodec_free_context(&encodeCtx);
av_free(out_buffer);
fclose(fp);
//avcodec_free_context(&camDecodeCtx);
avformat_free_context(camFmtCtx);
av_dict_free(&options);
}