源自ffmpeg实战教程(三)音频PCM采样为AAC,视频YUV编码为H264/HEVC
1、没有使用AVFormatContext
2、一帧图像的Y U V 独立读取,独立编码,独立写入?
关键代码:
#if TEST_HEVC
AVCodecID codec_id=AV_CODEC_ID_HEVC;
char filename_out[]="ws.hevc";
#else
AVCodecID codec_id=AV_CODEC_ID_H264;
char filename_out[]="ws.h264";
#endif
int framenum=100;
//没有使用AVFormate
avcodec_register_all();
pCodec = avcodec_find_encoder(codec_id);
pCodecCtx = avcodec_alloc_context3(pCodec);
pCodecCtx->bit_rate = 400000;
pCodecCtx->width = 480;
pCodecCtx->height = 272;
pCodecCtx->time_base.num=1;
pCodecCtx->time_base.den=25;
pCodecCtx->gop_size = 10;
pCodecCtx->max_b_frames = 1;
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264) av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);
avcodec_open2(pCodecCtx, pCodec, NULL)
pFrame = av_frame_alloc();
pFrame->format = pCodecCtx->pix_fmt;
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, 16);
#Encode
y_size = pCodecCtx->width * pCodecCtx->height;
for (i = 0; i < framenum; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
//Read raw YUV data
if (fread(pFrame->data[0],1,y_size,fp_in)<= 0|| // Y || 前面为真则忽略后面 前面为假则判断后面
fread(pFrame->data[1],1,y_size/4,fp_in)<= 0|| // U
fread(pFrame->data[2],1,y_size/4,fp_in)<= 0){ // V
return -1;
}else if(feof(fp_in)){
break;
}
#encode the image
pFrame->pts = i;
/* encode the image */
avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
if (got_output) {
printf("Succeed to encode frame: %5d\tsize:%5d\n",framecnt,pkt.size);
framecnt++;
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
#Flush Encoder
for (got_output = 1; got_output; i++) {
avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
if (got_output) {
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",pkt.size);
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}
MP4转AVI
1、音频压缩码流从一种封装格式文件中获取出来然后打包成另外一种封装格式的文件
2、不需要进行视音频的编码和解码
3.、思路:程序包含了对两个文件的处理:读取输入文件和写入输出文件。然后使用了一个avcodec_copy_context()拷贝输入的AVCodecContext到输出的AVCodecContext。然后再从输出的AVCodecContext写进输出文件
int main(int argc, char* argv[])
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
const char *in_filename, *out_filename;
int ret, i;
int frame_index=0;
in_filename = "ws.mp4";//Input file URL
out_filename = "ws.avi";//Output file URL
av_register_all();
#Input
avformat_open_input(&ifmt_ctx, in_filename, 0, 0);
avformat_find_stream_info(ifmt_ctx, 0);
#Output
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);// 初始化AVStream
//关键:Copy the settings of AVCodecContext
avcodec_copy_context(out_stream->codec, in_stream->codec);
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
#Open output file
if (!(ofmt->flags & AVFMT_NOFILE)) {
avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
}
avformat_write_header(ofmt_ctx, NULL);
#Encode
while (1) {
AVStream *in_stream, *out_stream;
av_read_frame(ifmt_ctx, &pkt);
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
//Convert PTS/DTS
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
av_interleaved_write_frame(ofmt_ctx, &pkt);
printf("Write %8d frames to output file\n",frame_index);
av_free_packet(&pkt);
frame_index++;
}
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return 0;
}