Android_调用ffmpeg_把截取视频保存为ppm文件

来源:互联网 发布:社交软件用户量 编辑:程序博客网 时间:2024/06/08 03:58

 

ppm文件是一种图像文件,有其自己的文件格式。
ppm文件由两个部分组成:第一个部分是三行ASCII码,这个部分决定了图像的存储
格式以及图像的特征;第二个部分就是图像的数据部分,图像就是由这个部分组成的。

ppm的第一部分由三行ASCII码组成
第一行是P2/P3/P6
第二行是图像的大小,先是列像素数,后是行像素数,中间有一个空格
第三行是一个介于1和65535之间的整数,而且必须是文本的,用来表示每一个像素
的一个分量用几个比特表示。

三行之后是图像的数据流,从左到右,从上到下。在进行图像数据存储的时候,需要进行
数据的格式,假如需要的像素值在0~255之间,那么在进行数据文件保存的时候,所写入
文件的值就必须是以%c的形式输入,而且数据之间没有明显的分离字符,图像处理软件会
自动地识别这些像素的值,并给予处理。

 

0A 是换行

 

 

#include <jni.h>#include <stdio.h>#include <android/log.h>#include "com_test_jni_InterfaceForJNI.h"#include <libavcodec/avcodec.h>#include <libavdevice/avdevice.h>#include <libavformat/avformat.h>#include <libavfilter/avfilter.h>#include <libavutil/avutil.h>#include <libavutil/mem.h>#include <libswscale/swscale.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#define  LOG_TAG    "FFMPEG-JNI"#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)void save_frame(AVFrame *pFrame, int width, int height, int iFrame);#define VIDEO_PATH "/sdcard/video.mp4"#define SAVE_FRAME_PATH  "/sdcard/video"int isDebug = 0;AVFormatContext *pFormatCtx; //这个结构体描述了一个媒体文件或媒体流的构成和基本信息AVCodecContext *pCodecCtx; // 这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息AVCodec *pCodec;void JNICALL Java_com_test_jni_InterfaceForJNI_testJNI(JNIEnv * env,jobject obj) {LOGI("HELLO JNI");LOGI("version = %d", avcodec_version());int ret;int err;int i, videoindex;//注册所有的文件格式和编解码器的库,只需要调用一次av_register_all();LOGE("Registered formats");//打开视频文件。这个函数会读取视频文件头部信息并保存在AVFormatContext中err = avformat_open_input(&pFormatCtx, VIDEO_PATH, NULL, NULL);LOGE("Called open file");if (err != 0) {LOGE("Couldn't open file");return;}LOGE("Opened file");//给每个流的AVStream结构体赋值,其实该函数已经完整走完了解码流程if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {LOGE("Unable to get stream info");return;}videoindex = -1;for (i = 0; i < pFormatCtx->nb_streams; i++)if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {videoindex = i;break;}if (videoindex == -1) {LOGE("Didn't find a video stream!");return;}LOGE("find stream info!");//初始化编解码信息pCodecCtx = pFormatCtx->streams[videoindex]->codec;//根据编解码信息查找解码器pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL) {LOGE("Could not found codec!");return;}LOGE("find codec!");//打开解码器if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {LOGE("Could not open codec!");return;}LOGE("codec the video ok!");//如果参数为1,会报  Fatal signal 11 错误//av_dump_format(pFormatCtx, 0, VIDEO_PATH, 0);AVFrame *pFrame, *pFrameRGB;struct SwsContext *pSwsCtx;AVPacket packet;int pictureSize;int frameFinished;uint8_t *buf;pFrame = av_frame_alloc(); //为该帧图像分配内存 avcodec_alloc_frame 废弃pFrameRGB = av_frame_alloc(); //为该帧图像分配内存pictureSize = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,pCodecCtx->height);buf = (uint8_t*) av_malloc(pictureSize);LOGE("pictureSize: %d\n", pictureSize);//已经分配的空间的结构体AVPicture挂上一段用于保存数据的空间avpicture_fill((AVPicture *) pFrameRGB, buf, PIX_FMT_BGR24,pCodecCtx->width, pCodecCtx->height);//设置图像转换上下文pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);i = 0;int flag = 0;//av_read_frame,读取码流中的音频若干帧或者视频一帧while (av_read_frame(pFormatCtx, &packet) >= 0 && flag < 2) {if (packet.stream_index == videoindex) {//的作用是解码一帧视频数据。输入一个压缩编码的结构体AVPacket,输出一个解码后的结构体AVFrame。该函数的声明位于libavcodec\avcodec.havcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);LOGE("decode one frame: %d", frameFinished);//为0说明没有找到可以解压的帧if (frameFinished) {flag++;//将yuv格式转换为RGB32sws_scale(pSwsCtx, (const uint8_t* const *) pFrame->data,pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,pFrameRGB->linesize);//保存该帧图片为PPM格式save_frame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);}}av_free_packet(&packet);}LOGE("decode finished!");sws_freeContext(pSwsCtx);av_free(pFrame);av_free(pFrameRGB);avcodec_close(pCodecCtx);avformat_close_input(&pFormatCtx);}void save_frame(AVFrame *pFrame, int width, int height, int iFrame) {FILE *pFile;char szFilename[32];int y;// Open filesprintf(szFilename, "%s/frame%d.ppm", SAVE_FRAME_PATH, iFrame);pFile = fopen(szFilename, "wb");if (pFile == NULL)return;// Write headerfprintf(pFile, "P6\n%d %d\n255\n", width, height);// Write pixel datafor (y = 0; y < height; y++)fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);// Close filefclose(pFile);}


 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击