#include <stdio.h>
#include <stdint.h>
#include <conio.h>
extern "C" {
#include "libavutil/imgutils.h"
#include "libavformat/avformat.h"
#include "libavutil/samplefmt.h"
#include "libavcodec/avcodec.h"
}
#define errReport(info, val) do{ \
fprintf(stderr, "ERR(func=%s,line=%d): %s code=%d\n",__FUNCTION__, __LINE__, info, val);\
getch();\
exit(0);\
}while (0);
const char *src_filename = NULL;
const char *video_dst_filename = NULL;
const char *audio_dst_filename = NULL;
FILE *pOutputAudio = NULL;
FILE *pOutputVideo = NULL;
AVStream *st = NULL;
AVCodec *dec = NULL;
AVCodecContext *dec_ctx = NULL;
AVFormatContext *fmt_ctx = NULL;
AVStream *videoStream = NULL, *audioStream = NULL;
AVCodecContext *videoDecCtx = NULL, *audioDecCtx = NULL;
int frame_width = 0, frame_height = 0;
enum AVPixelFormat pix_fmt;
unsigned char *video_dst_data[4];
int video_dst_linesize[4];
int video_dst_bufsize;
AVFrame *frame = NULL;
AVPacket packet;
int decode_packet(int *got_frame) {
int ret = 0;
*got_frame = 0;
if (packet.stream_index == videoStream->index) {
ret = avcodec_decode_video2(videoDecCtx, frame, got_frame, &packet);
if (ret < 0) return -1;
if (*got_frame) {
printf("Decode 1 frame.\n");
/* copy decoded frame to destination buffer:
* this is required since rawvideo expects non aligned data */
av_image_copy(video_dst_data, video_dst_linesize, (const unsigned char **)frame->data,
frame->linesize, pix_fmt, frame_width, frame_height);
fwrite(video_dst_data[0], 1, video_dst_bufsize, pOutputVideo);
}
}
else if (packet.stream_index == audioStream->index) {
ret = avcodec_decode_audio4(audioDecCtx, frame, got_frame, &packet);
if (ret < 0) return -2;
if (*got_frame) {
/*av_get_bytes_per_sample((enum AVSampleFormat)frame->format)返回的是采样位数16bits or 8 bits,
此函数进行了右移操作,即除以8来获得字节数nb_samples指每个声道每一帧所包含的采样个数*/
size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
fwrite(frame->extended_data[0], 1, unpadded_linesize, pOutputAudio);
}
}
return FFMIN(ret, packet.size);
}
int open_codec_context(enum AVMediaType type) {
int ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
if (ret < 0) return -1;
st = fmt_ctx->streams[ret];
dec_ctx = st->codec;
dec = avcodec_find_decoder(dec_ctx->codec_id);
if (!dec) return -2;
ret = avcodec_open2(dec_ctx, dec, NULL);
if (ret < 0) return -3;
return 0;
}
int main(int argc, char **argv) {
int ret, got_frame = 0;
src_filename = "test.mp4";
video_dst_filename = "out1.yuv";
audio_dst_filename = "out1.pcm";
av_register_all();
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0)
errReport("avformat_open_input", -1);
if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
errReport("avformat_find_stream_info", -1);
if ((ret = open_codec_context(AVMEDIA_TYPE_VIDEO)) < 0)
errReport("open_codec_context:VIDEO", ret);
videoStream = st;
videoDecCtx = dec_ctx;
frame_width = videoDecCtx->width;
frame_height = videoDecCtx->height;
pix_fmt = videoDecCtx->pix_fmt;
/*分配像素的存储空间该函数的四个参数分别表示AVFrame结构中的缓存指针、各个颜色分量的宽度、
图像分辨率(宽、高)、像素格式和内存对其的大小。该函数会返回分配的内存的大小。
其实就是对video_dst_data,video_dst_linesize内存进行分配*/
ret = av_image_alloc(video_dst_data, video_dst_linesize, frame_width, frame_height, pix_fmt, 1);
if (ret < 0) errReport("av_image_alloc", ret);
video_dst_bufsize = ret;
printf("av image alloc size:%d\n", video_dst_bufsize);
if (!(pOutputVideo = fopen(video_dst_filename, "wb")))
errReport("fopen:video_dst_filename", -1);
if ((ret = open_codec_context(AVMEDIA_TYPE_AUDIO)) < 0)
errReport("open_codec_context:AUDIO", ret);
audioStream = st;
audioDecCtx = dec_ctx;
if (!(pOutputAudio = fopen(audio_dst_filename, "wb")))
errReport("fopen:audio_dst_filename", -1);
av_dump_format(fmt_ctx, 0, src_filename, 0);
frame = av_frame_alloc();
if (!frame) errReport("av_frame_alloc", -1);
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;
while (av_read_frame(fmt_ctx, &packet) >= 0){
do{
ret = decode_packet(&got_frame);
printf("decode packet size:%d\n", ret);
packet.data += ret;
packet.size -= ret;
} while (packet.size > 0);
}
packet.data = NULL;
packet.size = 0;
do{
ret = decode_packet(&got_frame);
packet.data += ret;
packet.size -= ret;
} while (got_frame);
avcodec_close(videoDecCtx);
avcodec_close(audioDecCtx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
av_free(video_dst_data[0]);
fclose(pOutputAudio);
fclose(pOutputVideo);
return 0;
}
ffmpeg将mp4解封装为yuv以及pcm测试代码2
最新推荐文章于 2024-05-24 10:43:23 发布