#include "libavutil/avutil.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/parseutils.h"
#include "libavutil/imgutils.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;
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;
void saveBMP(const char *fileName, unsigned char *rgbData, int width, int height)
{
int bmpDataSize = width * height * 3;
BITMAPFILEHEADER bmpFileHeader = {0};
bmpFileHeader.bfType = 0x4d42;
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpDataSize;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bmpInfoHeader = {0};
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = width;
bmpInfoHeader.biHeight = height * (-1);
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
FILE *fp = fopen(fileName, "wb");
fwrite(&bmpFileHeader, 1, sizeof(BITMAPFILEHEADER), fp);
fwrite(&bmpInfoHeader, 1, sizeof(BITMAPINFOHEADER), fp);
fwrite(rgbData, 1, bmpDataSize, fp);
fclose(fp);
}
int frameCount = 0;
int decodeVideo(AVCodecContext *codecCtx, AVPacket *packet, struct SwsContext *swsCtx,
int destWidth, int destHeight, AVFrame *destFrame, FILE *dest_fp)
{
int ret = avcodec_send_packet(codecCtx, packet);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "send packet failed: %s\n", av_err2str(ret));
return -1;
}
AVFrame *frame = av_frame_alloc();
while (avcodec_receive_frame(codecCtx, frame) == 0)
{
sws_scale(swsCtx, (const uint8_t *const *)frame->data, frame->linesize, 0,
codecCtx->height, destFrame->data, destFrame->linesize);
#if 0
fwrite(frame->data[0], 1, destWidth * destHeight, dest_fp);
fwrite(frame->data[1], 1, destWidth * destHeight / 4, dest_fp);
fwrite(frame->data[2], 1, destWidth * destHeight / 4, dest_fp);
#endif
//rgb转BMP
fwrite(destFrame->data[0], 1, destWidth * destHeight * 3, dest_fp);
char bmpFileName[64] = {0};
snprintf(bmpFileName, sizeof(bmpFileName), "./picture/%d.bmp", frameCount);
saveBMP(bmpFileName, destFrame->data[0], destWidth, destHeight);
frameCount++;
av_log(NULL, AV_LOG_INFO, "frameCount: %d\n", frameCount);
av_log(NULL, AV_LOG_INFO, "linesize[0] = %d, linesize[1] = %d, linesize[2] = %d, width = %d, height = %d\n",
destFrame->linesize[0], destFrame->linesize[1], destFrame->linesize[2], destWidth, destHeight);
}
if (frame)
{
av_frame_free(&frame);
}
return 0;
}
int main(int argc, char const *argv[])
{
av_log_set_level(AV_LOG_INFO);
if (argc < 4)
{
av_log(NULL, AV_LOG_ERROR, "Usage: %s \n", argv[0]);
return -1;
}
const char *infileName = argv[1];
const char *outfileName = argv[2];
const char *destVideoSizeString = argv[3];
int destWidth = 0, destHeight = 0;
int ret = av_parse_video_size(&destWidth, &destHeight, destVideoSizeString);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "invalid video size: %s\n", destVideoSizeString);
return -1;
}
av_log(NULL, AV_LOG_INFO, "destWidth: %d, destHeight: %d\n", destWidth, destHeight);
AVFormatContext *inFmtCtx = NULL;
ret = avformat_open_input(&inFmtCtx, infileName, NULL, NULL);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "open input file: %s failed: %s\n", infileName, av_err2str(ret));
return -1;
}
ret = avformat_find_stream_info(inFmtCtx, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "find input stream failed: %s\n", av_err2str(ret));
goto fail;
}
ret = av_find_best_stream(inFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "find input best stream failed: %s\n", av_err2str(ret));
goto fail;
}
int videoIndex = ret;
AVCodecContext *codecCtx = avcodec_alloc_context3(NULL);
if (codecCtx == NULL)
{
av_log(NULL, AV_LOG_ERROR, "alloc avcodec context failed\n");
ret = -1;
goto fail;
}
avcodec_parameters_to_context(codecCtx, inFmtCtx->streams[videoIndex]->codecpar);
AVCodec *decoder = avcodec_find_decoder(codecCtx->codec_id);
if (decoder == NULL)
{
av_log(NULL, AV_LOG_ERROR, "find decoder failed, codec_id: %d\n", codecCtx->codec_id);
ret = -1;
goto fail;
}
ret = avcodec_open2(codecCtx, decoder, NULL);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "open decoder failed: %s\n", av_err2str(ret));
goto fail;
}
//enum AVPixelFormat destPixFmt = codecCtx->pix_fmt;
//rgb转BMP
//enum AVPixelFormat destPixFmt = AV_PIX_FMT_RGB24;
enum AVPixelFormat destPixFmt = AV_PIX_FMT_BGR24;
struct SwsContext *swsCtx = sws_getContext(codecCtx->width, codecCtx->height, codecCtx->pix_fmt, destWidth,
destHeight, destPixFmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (swsCtx == NULL)
{
av_log(NULL, AV_LOG_ERROR, "get sws context failed\n");
ret = -1;
goto fail;
}
AVFrame *destFrame = av_frame_alloc();
uint8_t *outBuffer = av_malloc(av_image_get_buffer_size(destPixFmt, destWidth, destHeight, 1));
av_image_fill_arrays(destFrame->data, destFrame->linesize, outBuffer, destPixFmt, destWidth, destHeight, 1);
FILE *dest_fp = fopen(outfileName, "wb+");
if (dest_fp == NULL)
{
av_log(NULL, AV_LOG_ERROR, "open outfile: %s failed\n", outfileName);
ret = -1;
goto fail;
}
AVPacket packet;
av_init_packet(&packet);
while (av_read_frame(inFmtCtx, &packet) >= 0)
{
if (packet.stream_index == videoIndex)
{
if (decodeVideo(codecCtx, &packet, swsCtx, destWidth, destHeight, destFrame ,dest_fp) == -1)
{
ret = -1;
av_packet_unref(&packet);
goto fail;
}
}
av_packet_unref(&packet);
}
//flush decoder
decodeVideo(codecCtx, NULL, swsCtx, destWidth, destHeight, destFrame ,dest_fp);
fail:
if (inFmtCtx)
{
avformat_close_input(&inFmtCtx);
}
if (codecCtx)
{
avcodec_free_context(&codecCtx);
}
if (dest_fp)
{
fclose(dest_fp);
}
if (destFrame)
{
av_frame_free(&destFrame);
}
if (outBuffer)
{
av_freep(&outBuffer);
}
return ret;
}
图片有点奇怪,
解决:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)