ffmpeg提取YUV和PCM
2017-03-15 13:06
204 查看
最近在学数字音视频的课,就研究了下如何从一个视频文件中提取视频流存为YUV以及提取视频文件中的音频文件存为PCM。
由于我是初学者,对于ffmpeg并不是很熟悉,在这里大的框架主要还是参考了雷大神的代码。
话不多说,直接上代码,如下:
代码中的音频部分是在现有的代码框架基础上添加的,主要是仿照视频进行了类比编写。运行代码之后,我们会得到两个文件。一个是testVideo.yuv,另一个是testAudio.pcm。
我们可以使用ffplay打开文件:
打开yuv文件
需要注意的是这里的width和height不可以乱填,乱填打开会花屏。width和height的信息我在代码中也有输出。
打开pcm文件
由于我是初学者,对于ffmpeg并不是很熟悉,在这里大的框架主要还是参考了雷大神的代码。
话不多说,直接上代码,如下:
#include <stdio.h> #define __STDC_CONSTANT_MACROS extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" }; int main(int argc, char* argv[]) { AVFormatContext *pFormatCtx; int i, videoindex,audioindex; AVCodecContext *pCodecCtx,*iaCodecCtx; AVCodec *pCodec,*iaCodec; AVFrame *pFrame,*pFrameYUV,*aFrame; uint8_t *out_buffer,*buffer; AVPacket *packet; int y_size; int ret, got_picture; struct SwsContext *img_convert_ctx; //输入文件路径 char filepath[]="Titanic.ts"; int frame_cnt = 0; av_register_all(); //avformat_network_init(); pFormatCtx = avformat_alloc_context(); if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){ printf("Couldn't open input stream.\n"); return -1; } if(avformat_find_stream_info(pFormatCtx,NULL)<0){ printf("Couldn't find stream information.\n"); return -1; } videoindex=-1; audioindex = -1; for (i = 0; i < pFormatCtx->nb_streams; i++){ if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){ videoindex=i; break; } } for (i = 0; i < pFormatCtx->nb_streams; i++){ if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){ audioindex = i; break; } } if(videoindex==-1){ printf("Didn't find a video stream.\n"); return -1; } if (audioindex == -1){ printf("Didn't find a audio stream.\n"); return -1; } pCodecCtx=pFormatCtx->streams[videoindex]->codec; pCodec=avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL){ printf("Codec not found.\n"); return -1; } if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){ printf("Could not open codec.\n"); return -1; } //audio iaCodecCtx = pFormatCtx->streams[audioindex]->codec; iaCodec = avcodec_find_decoder(iaCodecCtx->codec_id); if (iaCodec == NULL){ printf("Codec not found.\n"); return -1; } if (avcodec_open2(iaCodecCtx, iaCodec, NULL)<0){ printf("Could not open codec.\n"); return -1; } /* * 在此处添加输出视频信息的代码 * 取自于pFormatCtx,使用fprintf() */ pFrame=av_frame_alloc(); pFrameYUV=av_frame_alloc(); out_buffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)); avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); packet=(AVPacket *)av_malloc(sizeof(AVPacket)); //Output Info----------------------------- printf("--------------- File Information ----------------\n"); av_dump_format(pFormatCtx,0,filepath,0); printf("-------------------------------------------------\n"); img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); //audio buffer = (uint8_t*)malloc(1024); aFrame = avcodec_alloc_frame(); int len = 0; int pktsize = 0; uint8_t * pktdata; //读入YUV以及PCM文件,并以指针的形式存储 FILE *PYUV = fopen("testVideo.yuv","wb+"); FILE *PCM = fopen("testAudio.pcm", "wb+"); frame_cnt=0; while(av_read_frame(pFormatCtx, packet)>=0){ if(packet->stream_index==videoindex){ /* * 在此处添加输出H264码流的代码 * 取自于packet,使用fwrite() */ ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if(ret < 0){ printf("Decode Error.\n"); return -1; } 4000 if(got_picture){ sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); printf("Decoded frame index: %d\n",frame_cnt); /* * 在此处添加输出YUV的代码 * 取自于pFrameYUV,使用fwrite() */ //write YUV y_size = pCodecCtx->width*pCodecCtx->height; fwrite(pFrameYUV->data[0], 1, y_size, PYUV); fwrite(pFrameYUV->data[1], 1, y_size / 4, PYUV); fwrite(pFrameYUV->data[2], 1, y_size / 4, PYUV); frame_cnt++; } } //找到音频流 if (packet->stream_index == audioindex){ while (packet->size>0) { int size; len = avcodec_decode_audio4(iaCodecCtx, aFrame, &size, packet); if (len < 0){ pktsize = 0; printf("Error while decoding\n"); continue; } if (size){ int data_size = av_samples_get_buffer_size(NULL, iaCodecCtx->channels, aFrame->nb_samples, iaCodecCtx->sample_fmt, 1); fwrite(aFrame->data[0], 1, aFrame->linesize[0], PCM); } packet->size -= len; packet->data += len; } } av_free_packet(packet); } //**这里输出视频宽度和高度信息** printf("width : %d\n",pCodecCtx->width); printf("height : %d\n", pCodecCtx->height); sws_freeContext(img_convert_ctx); fclose(PYUV); fclose(PCM); //audio av_frame_free(&aFrame); avcodec_close(iaCodecCtx); av_frame_free(&pFrameYUV); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); getchar(); return 0; }
代码中的音频部分是在现有的代码框架基础上添加的,主要是仿照视频进行了类比编写。运行代码之后,我们会得到两个文件。一个是testVideo.yuv,另一个是testAudio.pcm。
我们可以使用ffplay打开文件:
打开yuv文件
ffplay -f rawvideo -video_size width*height testVideo.yuv
需要注意的是这里的width和height不可以乱填,乱填打开会花屏。width和height的信息我在代码中也有输出。
打开pcm文件
ffplay -f s16le testAudio.pcm
相关文章推荐
- [ffmpeg] play YUV/PCM with ffmpeg/ffplay
- 笔记:ffmpeg使用实例(bgr->yuv->h264, pcm->aac,加入音频重采样)
- 笔记:ffmpeg使用实例:bgr->yuv->h264,pcm->aac,没有音频重采样
- NDK开发——FFmpeg实现视频转YUV、视频转RGB显示、音频转PCM、音频播放、音视频同步
- 笔记:ffmpeg使用实例:yuv->h264,pcm->aac
- ffmpeg将mp4解封装为yuv以及pcm测试代码
- ffmpeg提取音频存为PCM
- ffmpeg提取音频存为PCM
- ffmpeg将mp4解封装为yuv以及pcm测试代码2
- (转) 从ffmpeg中提取出YUV数据
- [FFMPEG-1]最想实现的第一个功能-从mp3中提取pcm数据
- ffmpeg实战教程(三)音频PCM采样为AAC,视频YUV编码为H264/HEVC
- [FFMPEG-2]最想实现的第一点一个功能-从mp3中提取pcm数据,重采样和加wav头
- 将提取出的yuv三个分量序列合并成一个完整的彩色yuv序列(matlab实现)
- YUV格式详细解释与FFMPEG的关系
- ffmpeg 库yuv420转jpeg(内存)
- ffmpeg转yuv到h264
- 用ffmpeg把H264数据流解码成YUV420P
- iOS FFmpeg实时YUV420P编码H264
- ffmpeg 从mp4上提取H264的nalu