diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..bf075d0 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/work/dana_work/gopath/src/github.com/lucish/convert-video/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/app/main.go b/app/main.go deleted file mode 100644 index f88920a..0000000 --- a/app/main.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -/* -#include -#include -#include - - -int write_offset = 0; -char jpeg_data[100] = "this is test"; -int sayHello(char *src, int size) -{ - // int i = 0; - // for (i=0; i < size; i++){ - // printf("%c", *src+i); - // } - // printf("\n\n"); - return 0; -} - -char *test(char *src, int size) -{ - char *ret; - sayHello(src,size); - printf("c size %d\n", size); - ret = jpeg_data; - return ret; -} -*/ -import "C" -import ( - "fmt" - "io/ioutil" - "os" - "time" - "unsafe" -) - -var times = 1 - -//BenchmarkFFMpegC test -func BenchmarkFFMpegC(src []byte, size int) { - - var str string - - c_src := (*C.char)(unsafe.Pointer(&src[0])) // 转换 - c_int := (*C.int)(unsafe.Pointer(&size)) - // c_des := (*C.char)(unsafe.Pointer(&des[0])) // 转换 - for i := 0; i < times; i++ { - res := C.test(c_src, *c_int) - str = C.GoString(res) - // C.free(unsafe.Pointer(res)) - } - data := []byte(str) - WriteWithIoutil("/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.txt", data) - -} - -func main() { - var now, end time.Time - - inputFile := "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/src/testvack.h265" - // outputFile := "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.jpeg" - - src, err := ReadAll(inputFile) - fmt.Println(src) - fmt.Println("len: ", len(src)) - if err != nil || len(src) == 0 { - fmt.Println(err.Error()) - fmt.Println("read file err") - return - } - - now = time.Now() - BenchmarkFFMpegC(src, len(src)) - end = time.Now() - fmt.Printf("FFMpegC loop %d times, the cost time is %d\n", times, end.Sub(now)) -} - -func ReadAll(filePth string) ([]byte, error) { - f, err := os.Open(filePth) - defer f.Close() - if err != nil { - return nil, err - } - return ioutil.ReadAll(f) -} - -//使用ioutil.WriteFile方式写入文件,是将[]byte内容写入文件,如果content字符串中没有换行符的话,默认就不会有换行符 -func WriteWithIoutil(name string, content []byte) error { - if ioutil.WriteFile(name, content, 0644) == nil { - fmt.Println("写入文件成功") - } else { - fmt.Println("写入文件失败", content) - } - return nil -} diff --git a/bin/convert b/bin/convert deleted file mode 100755 index 2416b5a..0000000 Binary files a/bin/convert and /dev/null differ diff --git a/bin/test.jpeg b/bin/test.jpeg deleted file mode 100644 index 7a02ec9..0000000 Binary files a/bin/test.jpeg and /dev/null differ diff --git a/convert b/convert new file mode 100755 index 0000000..b90bbe5 Binary files /dev/null and b/convert differ diff --git a/convert.go b/convert.go new file mode 100644 index 0000000..31d7e3a --- /dev/null +++ b/convert.go @@ -0,0 +1,442 @@ +package main + +/* + +#cgo CFLAGS: -I/usr/local/ffmpeg/include +#cgo LDFLAGS:-L/usr/local/ffmpeg/lib -lavcodec -lavformat -lavfilter -lavutil -lavdevice -lswresample + +#include "libavfilter/avfilter.h" +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libavdevice/avdevice.h" +#include + +struct Input +{ + char *h265_data; + int offset; + int size; +}; + +struct Output +{ + char *jpeg_data; + int offset; +}; + +//函数声明 +int saveJpg(AVFrame *pFrame, struct Output *output_data); +//缓存1Mb +const int BUF_SIZE = 1048576; + +// const 32KB = 32768; +// char h265_data; //传入的h265文件 +// // char *h265_data; +// int read_true_size = 0; //h265文件实际大小 +// int read_offset = 0; //读取的偏移 + +// int write_offset = 0; +// uint8_t jpeg_data[1048576] = {"\0"}; +// uint8_t *jpeg_data = NULL; + +//读取数据的回调函数------------------------- +//AVIOContext使用的回调函数! +//注意:返回值是读取的字节数 +//手动初始化AVIOContext只需要两个东西:内容来源的buffer,和读取这个Buffer到FFmpeg中的函数 +//回调函数,功能就是:把buf_size字节数据送入buf即可 +//第一个参数(void *opaque)一般情况下可以不用 +int fill_iobuffer(void *opaque, uint8_t *buf, int buf_size) +{ + //从h256_data拷贝到buf中buf_size个字节 + + struct Input *data = (struct Input *)opaque; + // int read_offset = data->offset; + int size = data->size; + char *h265_data = data->h265_data; + + if (data->offset + buf_size - 1 < size) + { + //读取未溢出 直接复制 + memcpy(buf, h265_data + data->offset, buf_size); + data->offset += buf_size; + // printf("callback: read offset: %d\n", read_offset); + return buf_size; + } + else + { + //已经溢出无法读取 + if (data->offset >= size) + { + return -1; + } + else + { + //还有剩余字节未读取但不到buf_size 读取剩余字节 + int real_read = size - data->offset; + memcpy(buf, h265_data + data->offset, real_read); + data->offset += buf_size; + printf("callback: read offset: %d\n", data->offset); + return real_read; + } + } +} + +int convert(struct Input *input_data, struct Output *output_data) +{ + AVFormatContext *fmtCtx = NULL; // 文件格式管理 + const AVCodec *codec; // 定义解码器 + AVCodecContext *codeCtx = NULL; // 定义解码器上下文 + AVStream *stream = NULL; // 定义视频流 + int streamType; // 流类型 + AVCodecParameters *originPar = NULL; // 解码器的参数 + AVFrame *frame; // 帧 + AVPacket avpkt; // 数据包 + + //打开文件描述符 + // fp_open = fopen(inputFile, "rb+"); + fmtCtx = avformat_alloc_context(); + unsigned char *iobuffer = (unsigned char *)av_malloc(BUF_SIZE); + //初始化AVIOContext fill_iobuffer为自定的回调函数 + AVIOContext *avio = avio_alloc_context(iobuffer, BUF_SIZE, 0, input_data, fill_iobuffer, NULL, NULL); + fmtCtx->pb = avio; + + if (avformat_open_input(&fmtCtx, "nothing", NULL, NULL) < 0) // 成功返回0, 错误返回负值, 后两个参数用于指定文件格式 + { + printf("Error in open file"); + exit(0); + } + + if (avformat_find_stream_info(fmtCtx, NULL) < 0) // 失败返回负值 + { + printf("Error in find stream"); + exit(0); + } + + //av_dump_format(fmt_ctx, 0, inputFile, 0); // 打印控制信息 + av_init_packet(&avpkt); // 初始化数据包 + avpkt.data = NULL; + avpkt.size = 0; + + streamType = av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if (streamType < 0) + { + printf("Error in find best stream type"); + exit(0); + } + + originPar = fmtCtx->streams[streamType]->codecpar; // 获取流对应的解码器参数 + codec = avcodec_find_decoder(originPar->codec_id); // 根据解码器参数获取解码器 + if (!codec) + { // 未找到返回NULL + printf("Error in get the codec"); + exit(0); + } + + codeCtx = avcodec_alloc_context3(codec); // 初始化解码器上下文 + if (!codeCtx) + { + printf("Error in allocate the codeCtx"); + exit(0); + } + + if (avcodec_parameters_to_context(codeCtx, originPar) < 0) // 替换解码器上下文参数 + { + printf("Error in replace the parameters int the codeCtx"); + exit(0); + } + + avcodec_open2(codeCtx, codec, NULL); //打开解码器 + + frame = av_frame_alloc(); // 初始化帧, 用默认值填充字段 + if (!frame) + { + printf("Error in allocate the frame"); + exit(0); + } + + av_read_frame(fmtCtx, &avpkt); //从文件中读取一个数据包, 存储到avpkt中 + if (avpkt.stream_index == streamType) + { // 读取的数据包类型正确 + if (avcodec_send_packet(codeCtx, &avpkt) < 0) // 将数据包发送到解码器中 + { + printf("Error in the send packet"); + exit(0); + } + + while (avcodec_receive_frame(codeCtx, frame) == 0) + { + saveJpg(frame, output_data); + } + } + + av_packet_unref(&avpkt); +} + +//写文件的回调函数 +int write_buffer(void *opaque, uint8_t *buf, int buf_size) +{ + struct Output *data = (struct Output *)opaque; + + if (buf_size > BUF_SIZE) + { + return -1; + } + + memcpy(data->jpeg_data + data->offset, buf, buf_size); + data->offset += buf_size; + return buf_size; +} + +int saveJpg(AVFrame *pFrame, struct Output *output_data) +{ + int width = pFrame->width; + int height = pFrame->height; + AVCodecContext *pCodeCtx = NULL; + + //打开输出文件 + // fp_write = fopen(out_name, "wb+"); + AVFormatContext *pFormatCtx = NULL; + avformat_alloc_output_context2(&pFormatCtx, NULL, "mjpeg", NULL); + // AVFormatContext *pFormatCtx = avformat_alloc_context(); + // 设置输出文件格式 + // pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL); + + unsigned char *outbuffer = (unsigned char *)av_malloc(BUF_SIZE); + //新建一个AVIOContext 并与pFormatCtx关联 + AVIOContext *avio_out = avio_alloc_context(outbuffer, BUF_SIZE, 1, output_data, NULL, write_buffer, NULL); + pFormatCtx->pb = avio_out; + pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_FLUSH_PACKETS; + + // //创建并初始化输出AVIOContext + // if (avio_open(&pFormatCtx->pb, "./bin/nothing.jpeg", AVIO_FLAG_READ_WRITE) < 0) + // { + // printf("Couldn't open output file.\n"); + // return -1; + // } + + // 构建一个新stream + AVStream *pAVStream = avformat_new_stream(pFormatCtx, 0); + if (pAVStream == NULL) + { + return -1; + } + AVCodecParameters *parameters = pAVStream->codecpar; + parameters->codec_id = pFormatCtx->oformat->video_codec; + parameters->codec_type = AVMEDIA_TYPE_VIDEO; + parameters->format = AV_PIX_FMT_YUVJ420P; + parameters->width = pFrame->width; + parameters->height = pFrame->height; + + AVCodec *pCodec = avcodec_find_encoder(pAVStream->codecpar->codec_id); + + if (!pCodec) + { + printf("Could not find encoder\n"); + return -1; + } + + pCodeCtx = avcodec_alloc_context3(pCodec); + if (!pCodeCtx) + { + fprintf(stderr, "Could not allocate video codec context\n"); + return -1; + } + + if ((avcodec_parameters_to_context(pCodeCtx, pAVStream->codecpar)) < 0) + { + fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n", + av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); + return -1; + } + + pCodeCtx->time_base = (AVRational){1, 25}; + + if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0) + { + printf("Could not open codec."); + return -1; + } + + int ret = avformat_write_header(pFormatCtx, NULL); + if (ret < 0) + { + printf("write_header fail\n"); + return -1; + } + + int y_size = width * height; + + //Encode + // 给AVPacket分配足够大的空间 + AVPacket pkt; + av_new_packet(&pkt, y_size * 3); + + // 编码数据 + ret = avcodec_send_frame(pCodeCtx, pFrame); + if (ret < 0) + { + printf("Could not avcodec_send_frame."); + return -1; + } + + // 得到编码后数据 + ret = avcodec_receive_packet(pCodeCtx, &pkt); + if (ret < 0) + { + printf("Could not avcodec_receive_packet"); + return -1; + } + + // printf("av_write_frame\n"); + ret = av_write_frame(pFormatCtx, &pkt); + avio_flush(avio_out); + // printf("av_write_frame done\n"); + if (ret < 0) + { + printf("Could not av_write_frame"); + return -1; + } + // printf("av_packet_unref\n"); + av_packet_unref(&pkt); + + //Write Trailer + av_write_trailer(pFormatCtx); + // printf("av_write_trailer\n"); + + if (pFormatCtx->pb) + { + avio_context_free(&pFormatCtx->pb); + } + // printf("avio_free\n"); + + if (pFormatCtx) + { + avformat_free_context(pFormatCtx); + } + // printf("avformat_free_context\n"); + + if (pCodeCtx) + { + avcodec_close(pCodeCtx); + } + // printf("avcodec_close\n"); + + return 0; +} + +//返回des +int h265_to_jpeg(char *src, char *des, int input_size) +{ + // memcpy(h265_data, src, size); + // // h265_data = src; + // read_true_size = size; + struct Input input_data; + input_data.h265_data = src; + input_data.offset = 0; + input_data.size = input_size; + + struct Output output_data; + output_data.jpeg_data = des; + output_data.offset = 0; + + int err = 0; + err = convert(&input_data, &output_data); + if (err != 0) + { + return -1; + } + + // memcpy(des, jpeg_data, write_offset); + + return output_data.offset; +} +*/ +import "C" +import ( + "errors" + "fmt" + "io/ioutil" + + // _ "net/http/pprof" + "os" + "time" + "unsafe" +) + +func c_h265_to_jpeg(src []byte, size int) (des []byte, err error) { + des = make([]byte, 1048576) + c_src := (*C.char)(unsafe.Pointer(&src[0])) // 转换 + c_int := (*C.int)(unsafe.Pointer(&size)) + c_des := (*C.char)(unsafe.Pointer(&des[0])) // 转换 + res := C.h265_to_jpeg(c_src, c_des, *c_int) + // fmt.Println(res) + if res < 0 { + err = errors.New("C encode err!") + return + } + des = des[:res] + return +} + +var times = 10 + +//BenchmarkFFMpegC test +func BenchmarkFFMpegC(src []byte) { + + var des []byte + for i := 0; i < times; i++ { + func() { + des, _ = c_h265_to_jpeg(src, len(src)) + }() + + } + + WriteWithIoutil("./bin/testGo.jpeg", des) +} + +func main() { + var now, end time.Time + // go func() { + // log.Println(http.ListenAndServe("localhost:10000", nil)) + // }() + + //读取文件 + inputFile := "/work/dana_work/gopath/src/github.com/lucish/convert-video/src/huangxiao.h265" + src, err := ReadAll(inputFile) + if err != nil || len(src) == 0 { + fmt.Println(err.Error()) + fmt.Println("read file err") + return + } + fmt.Println("read file len: ", len(src)) + + fmt.Println("开始执行转码") + now = time.Now() + BenchmarkFFMpegC(src) + end = time.Now() + + fmt.Printf("FFMpegC loop %d times, the cost time is %d\n", times, end.Sub(now)) + // select {} +} + +func ReadAll(filePth string) ([]byte, error) { + f, err := os.Open(filePth) + defer f.Close() + if err != nil { + return nil, err + } + return ioutil.ReadAll(f) +} + +//使用ioutil.WriteFile方式写入文件,是将[]byte内容写入文件,如果content字符串中没有换行符的话,默认就不会有换行符 +func WriteWithIoutil(name string, content []byte) error { + if err := ioutil.WriteFile(name, content, 0644); err == nil { + fmt.Println("写入文件成功") + } else { + fmt.Println(err.Error()) + } + + return nil +} diff --git a/convert_file.c b/convert_file.c deleted file mode 100644 index 88d978c..0000000 --- a/convert_file.c +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include "libavcodec/avcodec.h" -#include "libavutil/avutil.h" -#include "libavutil/opt.h" -#include "libavdevice/avdevice.h" -#include - -int saveJpg(AVFrame *pFrame, const char *out_name); -char *ConvertDataToTargetFile(const char *inputFile, const char *outputFile) -{ - AVFormatContext *fmtCtx = NULL; // 文件格式管理 - const AVCodec *codec; // 定义解码器 - AVCodecContext *codeCtx = NULL; // 定义解码器上下文 - AVStream *stream = NULL; // 定义视频流 - int streamType; // 流类型 - AVCodecParameters *originPar = NULL; // 解码器的参数 - AVFrame *frame; // 帧 - AVPacket avpkt; // 数据包 - - if (avformat_open_input(&fmtCtx, inputFile, NULL, NULL) < 0) // 成功返回0, 错误返回负值, 后两个参数用于指定文件格式 - { - printf("Error in open file"); - exit(0); - } - - if (avformat_find_stream_info(fmtCtx, NULL) < 0) // 失败返回负值 - { - printf("Error in find stream"); - exit(0); - } - - //av_dump_format(fmt_ctx, 0, inputFile, 0); // 打印控制信息 - av_init_packet(&avpkt); // 初始化数据包 - avpkt.data = NULL; - avpkt.size = 0; - - streamType = av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); - if (streamType < 0) - { - printf("Error in find best stream type"); - exit(0); - } - - originPar = fmtCtx->streams[streamType]->codecpar; // 获取流对应的解码器参数 - codec = avcodec_find_decoder(originPar->codec_id); // 根据解码器参数获取解码器 - if (!codec) - { // 未找到返回NULL - printf("Error in get the codec"); - exit(0); - } - - codeCtx = avcodec_alloc_context3(codec); // 初始化解码器上下文 - if (!codeCtx) - { - printf("Error in allocate the codeCtx"); - exit(0); - } - - if (avcodec_parameters_to_context(codeCtx, originPar) < 0) // 替换解码器上下文参数 - { - printf("Error in replace the parameters int the codeCtx"); - exit(0); - } - - avcodec_open2(codeCtx, codec, NULL); //打开解码器 - - frame = av_frame_alloc(); // 初始化帧, 用默认值填充字段 - if (!frame) - { - printf("Error in allocate the frame"); - exit(0); - } - - av_read_frame(fmtCtx, &avpkt); //从文件中读取一个数据包, 存储到avpkt中 - if (avpkt.stream_index == streamType) - { // 读取的数据包类型正确 - if (avcodec_send_packet(codeCtx, &avpkt) < 0) // 将数据包发送到解码器中 - { - printf("Error in the send packet"); - exit(0); - } - - while (avcodec_receive_frame(codeCtx, frame) == 0) - { - saveJpg(frame, outputFile); - } - } - - av_packet_unref(&avpkt); -} - -int saveJpg(AVFrame *pFrame, const char *out_name) -{ - - int width = pFrame->width; - int height = pFrame->height; - AVCodecContext *pCodeCtx = NULL; - - AVFormatContext *pFormatCtx = avformat_alloc_context(); - // 设置输出文件格式 - pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL); - - // 创建并初始化输出AVIOContext - if (avio_open(&pFormatCtx->pb, out_name, AVIO_FLAG_READ_WRITE) < 0) - { - printf("Couldn't open output file."); - return -1; - } - - // 构建一个新stream - AVStream *pAVStream = avformat_new_stream(pFormatCtx, 0); - if (pAVStream == NULL) - { - return -1; - } - - AVCodecParameters *parameters = pAVStream->codecpar; - parameters->codec_id = pFormatCtx->oformat->video_codec; - parameters->codec_type = AVMEDIA_TYPE_VIDEO; - parameters->format = AV_PIX_FMT_YUVJ420P; - parameters->width = pFrame->width; - parameters->height = pFrame->height; - - AVCodec *pCodec = avcodec_find_encoder(pAVStream->codecpar->codec_id); - - if (!pCodec) - { - printf("Could not find encoder\n"); - return -1; - } - - pCodeCtx = avcodec_alloc_context3(pCodec); - if (!pCodeCtx) - { - fprintf(stderr, "Could not allocate video codec context\n"); - exit(1); - } - - if ((avcodec_parameters_to_context(pCodeCtx, pAVStream->codecpar)) < 0) - { - fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n", - av_get_media_type_string(AVMEDIA_TYPE_VIDEO)); - return -1; - } - - pCodeCtx->time_base = (AVRational){1, 25}; - - if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0) - { - printf("Could not open codec."); - return -1; - } - - int ret = avformat_write_header(pFormatCtx, NULL); - if (ret < 0) - { - printf("write_header fail\n"); - return -1; - } - - int y_size = width * height; - - //Encode - // 给AVPacket分配足够大的空间 - AVPacket pkt; - av_new_packet(&pkt, y_size * 3); - - // 编码数据 - ret = avcodec_send_frame(pCodeCtx, pFrame); - if (ret < 0) - { - printf("Could not avcodec_send_frame."); - return -1; - } - - // 得到编码后数据 - ret = avcodec_receive_packet(pCodeCtx, &pkt); - if (ret < 0) - { - printf("Could not avcodec_receive_packet"); - return -1; - } - - ret = av_write_frame(pFormatCtx, &pkt); - - if (ret < 0) - { - printf("Could not av_write_frame"); - return -1; - } - - av_packet_unref(&pkt); - - //Write Trailer - av_write_trailer(pFormatCtx); - - avcodec_close(pCodeCtx); - avio_close(pFormatCtx->pb); - avformat_free_context(pFormatCtx); - - return 0; -} - -int test() -{ - char *inputFile = "bigbuckbunny_480x272.h265"; - char *outputFile = "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.jpeg"; - ConvertDataToTargetFile(inputFile, outputFile); -} - -int main() -{ - char *inputFile = "test.h265"; - char *outputFile = "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.jpeg"; - ConvertDataToTargetFile(inputFile, outputFile); - return 0; -} \ No newline at end of file diff --git a/convert_test.go b/convert_test.go new file mode 100644 index 0000000..9ad9995 --- /dev/null +++ b/convert_test.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "testing" +) + +func BenchmarkConvert(b *testing.B) { + //读取文件 + inputFile := "/work/dana_work/gopath/src/github.com/lucish/convert-video/src/huangxiao.h265" + src, err := ReadAll(inputFile) + if err != nil || len(src) == 0 { + fmt.Println(err.Error()) + fmt.Println("read file err") + return + } + + for i := 0; i < b.N; i++ { + c_h265_to_jpeg(src, len(src)) + } + +} diff --git a/convert_stream.c b/cpp/convert_stream.c similarity index 74% rename from convert_stream.c rename to cpp/convert_stream.c index cef04c4..f77df3a 100644 --- a/convert_stream.c +++ b/cpp/convert_stream.c @@ -6,21 +6,33 @@ #include "libavdevice/avdevice.h" #include -int convert(); -int saveJpg(AVFrame *pFrame); +struct Input +{ + char *h265_data; + int offset; + int size; +}; -// FILE *fp_open; -//从文件中读取数据 分配1Mb空间 +struct Output +{ + char *jpeg_data; + int offset; +}; + +//函数声明 +int saveJpg(AVFrame *pFrame, struct Output *output_data); +//缓存1Mb const int BUF_SIZE = 1048576; -// const 32KB = 32768; -char h265_data[1048576] = {"\0"}; //传入的h265文件 -// char *h265_data; -int read_true_size = 0; //h265文件实际大小 -int read_offset = 0; //读取的偏移 -FILE *fp_write; -int write_offset = 0; -char jpeg_data[1048576] = {"\0"}; +// const 32KB = 32768; +// char h265_data; //传入的h265文件 +// // char *h265_data; +// int read_true_size = 0; //h265文件实际大小 +// int read_offset = 0; //读取的偏移 + +// int write_offset = 0; +// uint8_t jpeg_data[1048576] = {"\0"}; +// uint8_t *jpeg_data = NULL; //读取数据的回调函数------------------------- //AVIOContext使用的回调函数! @@ -32,34 +44,39 @@ int fill_iobuffer(void *opaque, uint8_t *buf, int buf_size) { //从h256_data拷贝到buf中buf_size个字节 - if (read_offset + buf_size - 1 < read_true_size) + struct Input *data = (struct Input *)opaque; + // int read_offset = data->offset; + int size = data->size; + char *h265_data = data->h265_data; + + if (data->offset + buf_size - 1 < size) { //读取未溢出 直接复制 - memcpy(buf, h265_data + read_offset, buf_size); - read_offset += buf_size; - printf("read offset: %d\n", read_offset); + memcpy(buf, h265_data + data->offset, buf_size); + data->offset += buf_size; + // printf("callback: read offset: %d\n", read_offset); return buf_size; } else { //已经溢出无法读取 - if (read_offset >= read_true_size) + if (data->offset >= size) { return -1; } else { //还有剩余字节未读取但不到buf_size 读取剩余字节 - int real_read = read_true_size - read_offset; - memcpy(buf, h265_data + read_offset, real_read); - read_offset += buf_size; - printf("read offset: %d\n", read_offset); + int real_read = size - data->offset; + memcpy(buf, h265_data + data->offset, real_read); + data->offset += buf_size; + printf("callback: read offset: %d\n", data->offset); return real_read; } } } -int convert() +int convert(struct Input *input_data, struct Output *output_data) { AVFormatContext *fmtCtx = NULL; // 文件格式管理 const AVCodec *codec; // 定义解码器 @@ -73,9 +90,9 @@ int convert() //打开文件描述符 // fp_open = fopen(inputFile, "rb+"); fmtCtx = avformat_alloc_context(); - unsigned char *iobuffer = (unsigned char *)av_malloc(1048576); + unsigned char *iobuffer = (unsigned char *)av_malloc(BUF_SIZE); //初始化AVIOContext fill_iobuffer为自定的回调函数 - AVIOContext *avio = avio_alloc_context(iobuffer, 1048576, 0, NULL, fill_iobuffer, NULL, NULL); + AVIOContext *avio = avio_alloc_context(iobuffer, BUF_SIZE, 0, input_data, fill_iobuffer, NULL, NULL); fmtCtx->pb = avio; if (avformat_open_input(&fmtCtx, "nothing", NULL, NULL) < 0) // 成功返回0, 错误返回负值, 后两个参数用于指定文件格式 @@ -143,7 +160,7 @@ int convert() while (avcodec_receive_frame(codeCtx, frame) == 0) { - saveJpg(frame); + saveJpg(frame, output_data); } } @@ -153,30 +170,19 @@ int convert() //写文件的回调函数 int write_buffer(void *opaque, uint8_t *buf, int buf_size) { + struct Output *data = (struct Output *)opaque; if (buf_size > BUF_SIZE) { return -1; } - memcpy(jpeg_data, buf, buf_size); - write_offset += buf_size; + memcpy(data->jpeg_data + data->offset, buf, buf_size); + data->offset += buf_size; return buf_size; - - // if (!feof(fp_write)) - // { - // int true_size = fwrite(buf, 1, buf_size, fp_write); - // write_offset += true_size; - // printf("write_offset: %d\n", write_offset); - // return true_size; - // } - // else - // { - // return -1; - // } } -int saveJpg(AVFrame *pFrame) +int saveJpg(AVFrame *pFrame, struct Output *output_data) { int width = pFrame->width; int height = pFrame->height; @@ -190,9 +196,9 @@ int saveJpg(AVFrame *pFrame) // 设置输出文件格式 // pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL); - unsigned char *outbuffer = (unsigned char *)av_malloc(1048576); + unsigned char *outbuffer = (unsigned char *)av_malloc(BUF_SIZE); //新建一个AVIOContext 并与pFormatCtx关联 - AVIOContext *avio_out = avio_alloc_context(outbuffer, 1048576, 1, NULL, NULL, write_buffer, NULL); + AVIOContext *avio_out = avio_alloc_context(outbuffer, BUF_SIZE, 1, output_data, NULL, write_buffer, NULL); pFormatCtx->pb = avio_out; pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_FLUSH_PACKETS; @@ -314,32 +320,45 @@ int saveJpg(AVFrame *pFrame) } //返回des -char *h265_to_jpeg(char *src, int size) +int h265_to_jpeg(char *src, char *des, int input_size) { - memcpy(h265_data, src, size); - // h265_data = src; - read_true_size = size; + // memcpy(h265_data, src, size); + // // h265_data = src; + // read_true_size = size; + struct Input input_data; + input_data.h265_data = src; + input_data.offset = 0; + input_data.size = input_size; + + struct Output output_data; + output_data.jpeg_data = des; + output_data.offset = 0; + int err = 0; - err = convert(); + err = convert(&input_data, &output_data); if (err != 0) { - return NULL; + return -1; } - return jpeg_data; + + // memcpy(des, jpeg_data, write_offset); + + return output_data.offset; } int main() { - char *inputFile = "/home/lucis/work/gopath/src/github.com/lucish/convert-video/src/test.h265"; + char *inputFile = "/work/dana_work/gopath/src/github.com/lucish/convert-video/src/huangxiao.h265"; FILE *fp_read; + FILE *fp_write; fp_read = fopen(inputFile, "rb+"); - char input[1048576]; + char h265_data[1048576], output[1048576]; int size = 0; //测试 将目标文件全部读取到h265_data中, true_size为文件实际大小 if (!feof(fp_read)) { - size = fread(input, 1, BUF_SIZE, fp_read); + size = fread(h265_data, 1, 1048576, fp_read); printf("一次读取全部文件 实际大小: %d\n", size); if (!size) { @@ -348,25 +367,30 @@ int main() } printf("h256 strlen: %ld\n", strlen(h265_data)); } - char *output = h265_to_jpeg(input, size); - printf("jpeg str len: %ld, write_offset: %d\n", strlen(output), write_offset); + int ret = h265_to_jpeg(h265_data, output, size); + + // printf("size of jpeg: %ld, write_offset: %d\n", sizeof(jpeg_data), write_offset); char *outputFile = "bin/test.jpeg"; + char *buf = (char *)malloc(ret + 1); + memset(buf, 0, ret + 1); + memcpy(buf, output, ret); //测试 将读取到的数据全部写入文件 fp_write = fopen(outputFile, "wb+"); if (!feof(fp_write)) { - int true_size = fwrite(output, 1, write_offset, fp_write); - write_offset += true_size; - // printf("write_offset: %d\n", write_offset); - // printf("write file success\n"); + int true_size = fwrite(buf, 1, ret, fp_write); } else { printf("write file err"); return 0; } + + free(buf); + // free(jpeg_data); + fclose(fp_read); fclose(fp_write); // printf("final read offset: %d\n", read_offset); diff --git a/run.sh b/cpp/run.sh similarity index 100% rename from run.sh rename to cpp/run.sh diff --git a/main.go b/main.go deleted file mode 100644 index f88920a..0000000 --- a/main.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -/* -#include -#include -#include - - -int write_offset = 0; -char jpeg_data[100] = "this is test"; -int sayHello(char *src, int size) -{ - // int i = 0; - // for (i=0; i < size; i++){ - // printf("%c", *src+i); - // } - // printf("\n\n"); - return 0; -} - -char *test(char *src, int size) -{ - char *ret; - sayHello(src,size); - printf("c size %d\n", size); - ret = jpeg_data; - return ret; -} -*/ -import "C" -import ( - "fmt" - "io/ioutil" - "os" - "time" - "unsafe" -) - -var times = 1 - -//BenchmarkFFMpegC test -func BenchmarkFFMpegC(src []byte, size int) { - - var str string - - c_src := (*C.char)(unsafe.Pointer(&src[0])) // 转换 - c_int := (*C.int)(unsafe.Pointer(&size)) - // c_des := (*C.char)(unsafe.Pointer(&des[0])) // 转换 - for i := 0; i < times; i++ { - res := C.test(c_src, *c_int) - str = C.GoString(res) - // C.free(unsafe.Pointer(res)) - } - data := []byte(str) - WriteWithIoutil("/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.txt", data) - -} - -func main() { - var now, end time.Time - - inputFile := "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/src/testvack.h265" - // outputFile := "/home/lucis/work/gopath/src/github.com/lucish/h265-to-JPEG/bin/test.jpeg" - - src, err := ReadAll(inputFile) - fmt.Println(src) - fmt.Println("len: ", len(src)) - if err != nil || len(src) == 0 { - fmt.Println(err.Error()) - fmt.Println("read file err") - return - } - - now = time.Now() - BenchmarkFFMpegC(src, len(src)) - end = time.Now() - fmt.Printf("FFMpegC loop %d times, the cost time is %d\n", times, end.Sub(now)) -} - -func ReadAll(filePth string) ([]byte, error) { - f, err := os.Open(filePth) - defer f.Close() - if err != nil { - return nil, err - } - return ioutil.ReadAll(f) -} - -//使用ioutil.WriteFile方式写入文件,是将[]byte内容写入文件,如果content字符串中没有换行符的话,默认就不会有换行符 -func WriteWithIoutil(name string, content []byte) error { - if ioutil.WriteFile(name, content, 0644) == nil { - fmt.Println("写入文件成功") - } else { - fmt.Println("写入文件失败", content) - } - return nil -}