diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..f197b45 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/usr/local/ffmpeg/include", + "${workspaceFolder}/libs_win/develop/SDL2-2.0.9/include" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "cppStandard": "c++98", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fbf1eb8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + {//包含Debug配置 + "name": "(gdb) 启动",//配置名称 + "type": "cppdbg",//配置类型,对应cpptools提供的调试功能 + "request": "launch",//请求配置类型,可以是启动/附加类型[launch/attach] + "program": "${workspaceFolder}/study_ffmpeg/7_/${fileBasenameNoExtension}",//待调试程序本地路径 + "args": [//程序调试时传递给程序的命令行参数,设为空值 + "build_avdio.h264", + "libx264" + ], + "stopAtEntry": false,//改为true时程序暂停在程序入口位置,即main处打上断点 + "cwd": "${fileDirname}",//调试程序时的工作目录,这里表示源码目录 + "environment": [],//环境变量,设为空值 + "externalConsole": false,//true:cmd窗口; false:Vscode的内置终端输出 + "MIMode": "gdb",//指定连接的调试器,minGW64中调试程序->gdb + "setupCommands": [ + { + "description": "为 gdb 启用整齐打印", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "将反汇编风格设置为 Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + }, + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2a0bda3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "C_Cpp.errorSquiggles": "enabled", + "files.associations": { + "stdio.h": "c", + "log.h": "c", + "gen_pic_rgb": "c", + "sdl.h": "c", + "avcodec.h": "c", + "avutil.h": "c" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5a1d0bc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,37 @@ +{ + "tasks": [ + {//构建配置项 + "type": "cppbuild", //任务类型,Vscode将预定义变量转义解析后直接传给command;shell->先打开shell再输入命令,因此args会经过shell再次解析 + "label": "C/C++: gcc 生成活动文件", //任务名称 + "command": "/usr/bin/gcc",//本地编译器路径 + "args": [//包含传给gcc命令的参数,用于实现特定功能 + "-g",//生成和调试有关的信息 + "${file}",//指定编译文件为当前文件 + "-o",//指定输出文件的路径和名称 + "${fileDirname}/${fileBasenameNoExtension}",//修改.exe文件生成位置 + "-lm", + "-I/usr/local/ffmpeg/include", + "-L/usr/local/ffmpeg/lib", + "-I/${workspaceFolder}/libs_win/develop/SDL2-2.0.9/include", + "-L/${workspaceFolder}/libs_win/develop/SDL2-2.0.9/lib", + "-lavutil", + "-lavformat", + "-lavcodec", + "-lswscale", + "-lSDL2" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": {//包含很多task,归为group + "kind": "build",//表名该组任务类型是构建 + "isDefault": true//表明此任务为此组任务中的默认任务 + }, + "detail": "调试器生成的任务。" + }, + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/audio.c b/audio.c index d5c66ac..2ce3564 100644 --- a/audio.c +++ b/audio.c @@ -1,6 +1,7 @@ #include "player.h" #include "packet.h" #include "frame.h" +#include "SDL_audio.h" static void sdl_audio_callback(void *opaque, Uint8 *stream, int len); diff --git a/demux.c b/demux.c index 0d97b0a..c03ac57 100644 --- a/demux.c +++ b/demux.c @@ -1,5 +1,7 @@ #include "demux.h" #include "packet.h" +#include "SDL_events.h" +#include "SDL_mutex.h" static int decode_interrupt_cb(void *ctx) { diff --git a/output/test_log b/output/test_log new file mode 100755 index 0000000..23a1fb9 Binary files /dev/null and b/output/test_log differ diff --git a/resources/clock.aac b/resources/clock.aac new file mode 100644 index 0000000..e69de29 diff --git a/resources/clock.h264 b/resources/clock.h264 new file mode 100644 index 0000000..e69de29 diff --git a/study_ffmpeg/5_/cut_avdio b/study_ffmpeg/5_/cut_avdio new file mode 100755 index 0000000..d76212c Binary files /dev/null and b/study_ffmpeg/5_/cut_avdio differ diff --git a/study_ffmpeg/5_/cut_avdio.c b/study_ffmpeg/5_/cut_avdio.c new file mode 100644 index 0000000..5f8d698 --- /dev/null +++ b/study_ffmpeg/5_/cut_avdio.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + double starttime; + double endtime; + + av_log_set_level(AV_LOG_DEBUG); + // cut src dst start end + if( argc < 5 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + starttime = atof(argv[3]); + endtime = atof(argv[4]); + + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 4.打开目的文件的上下文 + // AVFormatContext *oFmtCtx = avformat_alloc_context(); + // if( !oFmtCtx ){ + // av_log(NULL, AV_LOG_ERROR, "NO Memory!\n"); + // goto _ERROR; + // } + // const AVOutputFormat *outFmt = av_guess_format(NULL, dst, NULL); + // oFmtCtx->oformat = outFmt; + AVFormatContext *oFmtCtx = NULL; + avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst); + if( !oFmtCtx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + + int *stream_map = NULL; + int stream_idx = 0; + stream_map = av_calloc(pFmtCtx->nb_streams, sizeof(int)); + if( !stream_map ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + for( int i=0 ; i < pFmtCtx->nb_streams ; i++ ){ + AVStream *inStream = pFmtCtx->streams[i]; + AVStream *outStream = NULL; + AVCodecParameters *inCodecPar = inStream->codecpar; + if( inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO && + inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO && + inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE){ + stream_map[i] = -1; + continue; + } + else{ + stream_map[i] = stream_idx++ ; + outStream = avformat_new_stream(oFmtCtx, NULL); + if( !outStream ){ + av_log(oFmtCtx, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + avcodec_parameters_copy(outStream->codecpar, inStream->codecpar); + outStream->codecpar->codec_tag = 0; + } + } + + + // 绑定 + ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 7.写多媒体文件头到目的文件 + + ret = avformat_write_header(oFmtCtx, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + + // cut起作用的地方 + // 很多视频的裁剪不准确,是因为视频有IPB帧,我们很有可能裁剪到了B帧(没有I帧无法解析),那么就必须向前或者向后来裁剪 + // 这个函数表示,从流的哪个时间点截取文件 + ret = av_seek_frame(pFmtCtx, -1, starttime * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD); + + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret)); + goto _ERROR; + } + + + int64_t *dts_start_time = av_calloc(pFmtCtx->nb_streams, sizeof(int64_t)); + int64_t *pts_start_time = av_calloc(pFmtCtx->nb_streams, sizeof(int64_t)); + for( int i = 0 ; i < pFmtCtx->nb_streams ; i++ ){ + dts_start_time[i] = -1; + pts_start_time[i] = -1; + } + // 8.从源多媒体文件中读到音频/视频/字幕数据到目的文件中 + +// 0 1 2 3 4 5 +// -1 1 -1 1 -1 1 + +// 0 1 2 3 4 5 +// -1 0 -1 1 -1 2 + + AVPacket pkt; + while( av_read_frame(pFmtCtx, &pkt) >= 0) { + AVStream *inStream, *outStream; + + if( dts_start_time[pkt.stream_index] == -1 && pkt.dts > 0 ){ + dts_start_time[pkt.stream_index] = pkt.dts; + } + + if( pts_start_time[pkt.stream_index] == -1 && pkt.pts > 0 ){ + pts_start_time[pkt.stream_index] = pkt.pts; + } + + inStream = pFmtCtx->streams[pkt.stream_index]; + if( av_q2d(inStream->time_base) * pkt.pts > endtime ){ + av_log(oFmtCtx, AV_LOG_INFO, "success!\n"); + break; + } + + if( stream_map[pkt.stream_index] < 0 ){ + av_packet_unref(&pkt); + continue; + } + + pkt.pts = pkt.pts - pts_start_time[pkt.stream_index]; + pkt.dts = pkt.dts - dts_start_time[pkt.stream_index]; + if( pkt.pts > pkt.dts ){ + pkt.pts = pkt.dts; + } + + pkt.stream_index = stream_map[pkt.stream_index]; + + outStream = oFmtCtx->streams[pkt.stream_index]; + av_packet_rescale_ts(&pkt, inStream->time_base, outStream->time_base); + // pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + // pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + // pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base); + // pkt.stream_index = 0; + pkt.pos = -1; + av_interleaved_write_frame(oFmtCtx, &pkt); + av_packet_unref(&pkt); + } + + // 9.写多媒体文件尾到文件中 + + av_write_trailer(oFmtCtx); + + // 10.将申请的资源释放掉 + +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( oFmtCtx->pb ){ + avio_close(oFmtCtx->pb); + } + if( oFmtCtx ){ + avformat_free_context(oFmtCtx); + oFmtCtx = NULL; + } + if( stream_map ){ + av_free(stream_map); + } + if( dts_start_time ){ + av_free(dts_start_time); + + } + if( pts_start_time ){ + av_free(pts_start_time); + } + return 0; +} + diff --git a/study_ffmpeg/5_/extra_audio b/study_ffmpeg/5_/extra_audio new file mode 100755 index 0000000..0a59fe2 Binary files /dev/null and b/study_ffmpeg/5_/extra_audio differ diff --git a/study_ffmpeg/5_/extra_audio.c b/study_ffmpeg/5_/extra_audio.c new file mode 100644 index 0000000..31ab2e5 --- /dev/null +++ b/study_ffmpeg/5_/extra_audio.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + + av_log_set_level(AV_LOG_DEBUG); + if( argc < 3 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 3.从多媒体文件中找到视频流 + + int idx = -1; + idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if( idx < 0 ){ + av_log(pFmtCtx, AV_LOG_ERROR, "Dose not include audio stream!\n"); + goto _ERROR; + } + + // 4.打开目的文件的上下文 + AVFormatContext *oFmtCtx = avformat_alloc_context(); + if( !oFmtCtx ){ + av_log(NULL, AV_LOG_ERROR, "NO Memory!\n"); + goto _ERROR; + } + const AVOutputFormat *outFmt = av_guess_format(NULL, dst, NULL); + oFmtCtx->oformat = outFmt; + + + // 5.创建一个新的视频流 + AVStream *outStream = avformat_new_stream(oFmtCtx, NULL); + + + // 6.设置输出音频参数 + + AVStream *inStream = pFmtCtx->streams[idx]; + avcodec_parameters_copy(outStream->codecpar, inStream->codecpar); + outStream->codecpar->codec_tag = 0; + + + // 绑定 + ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 7.写多媒体文件头到目的文件 + + ret = avformat_write_header(oFmtCtx, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 8.从源多媒体文件中读到音频数据到目的文件中 + + AVPacket pkt; + while( av_read_frame(pFmtCtx, &pkt) >= 0) { + if( pkt.stream_index == idx ){ + pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + pkt.dts = pkt.pts; + pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base); + pkt.stream_index = 0; + pkt.pos = -1; + av_interleaved_write_frame(oFmtCtx, &pkt); + av_packet_unref(&pkt); + } + } + + // 9.写多媒体文件尾到文件中 + + av_write_trailer(oFmtCtx); + + // 10.将申请的资源释放掉 + +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( oFmtCtx->pb ){ + avio_close(oFmtCtx->pb); + } + if( oFmtCtx ){ + avformat_free_context(oFmtCtx); + oFmtCtx = NULL; + } + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/5_/extra_video b/study_ffmpeg/5_/extra_video new file mode 100755 index 0000000..b0bcd3a Binary files /dev/null and b/study_ffmpeg/5_/extra_video differ diff --git a/study_ffmpeg/5_/extra_video.c b/study_ffmpeg/5_/extra_video.c new file mode 100644 index 0000000..53a83f7 --- /dev/null +++ b/study_ffmpeg/5_/extra_video.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + + av_log_set_level(AV_LOG_DEBUG); + if( argc < 3 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 3.从多媒体文件中找到音频流 + + int idx = -1; + idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); + if( idx < 0 ){ + av_log(pFmtCtx, AV_LOG_ERROR, "Dose not include audio stream!\n"); + goto _ERROR; + } + + // 4.打开目的文件的上下文 + AVFormatContext *oFmtCtx = avformat_alloc_context(); + if( !oFmtCtx ){ + av_log(NULL, AV_LOG_ERROR, "NO Memory!\n"); + goto _ERROR; + } + const AVOutputFormat *outFmt = av_guess_format(NULL, dst, NULL); + oFmtCtx->oformat = outFmt; + + + // 5.创建一个新的视频流 + AVStream *outStream = avformat_new_stream(oFmtCtx, NULL); + + + // 6.设置输出视频参数 + + AVStream *inStream = pFmtCtx->streams[idx]; + avcodec_parameters_copy(outStream->codecpar, inStream->codecpar); + outStream->codecpar->codec_tag = 0; + + + // 绑定 + ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 7.写多媒体文件头到目的文件 + + ret = avformat_write_header(oFmtCtx, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 8.从源多媒体文件中读到音频数据到目的文件中 + + AVPacket pkt; + while( av_read_frame(pFmtCtx, &pkt) >= 0) { + if( pkt.stream_index == idx ){ + pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + + pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base); + pkt.stream_index = 0; + pkt.pos = -1; + av_interleaved_write_frame(oFmtCtx, &pkt); + av_packet_unref(&pkt); + } + } + + // 9.写多媒体文件尾到文件中 + + av_write_trailer(oFmtCtx); + + // 10.将申请的资源释放掉 + +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( oFmtCtx->pb ){ + avio_close(oFmtCtx->pb); + } + if( oFmtCtx ){ + avformat_free_context(oFmtCtx); + oFmtCtx = NULL; + } + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/5_/remux b/study_ffmpeg/5_/remux new file mode 100755 index 0000000..8c04ce8 Binary files /dev/null and b/study_ffmpeg/5_/remux differ diff --git a/study_ffmpeg/5_/remux.c b/study_ffmpeg/5_/remux.c new file mode 100644 index 0000000..c82f52a --- /dev/null +++ b/study_ffmpeg/5_/remux.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + + av_log_set_level(AV_LOG_DEBUG); + if( argc < 3 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 4.打开目的文件的上下文 + // AVFormatContext *oFmtCtx = avformat_alloc_context(); + // if( !oFmtCtx ){ + // av_log(NULL, AV_LOG_ERROR, "NO Memory!\n"); + // goto _ERROR; + // } + // const AVOutputFormat *outFmt = av_guess_format(NULL, dst, NULL); + // oFmtCtx->oformat = outFmt; + AVFormatContext *oFmtCtx = NULL; + avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst); + if( !oFmtCtx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + + int *stream_map = NULL; + int stream_idx = 0; + stream_map = av_calloc(pFmtCtx->nb_streams, sizeof(int)); + if( !stream_map ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + for( int i=0 ; i < pFmtCtx->nb_streams ; i++ ){ + AVStream *inStream = pFmtCtx->streams[i]; + AVStream *outStream = NULL; + AVCodecParameters *inCodecPar = inStream->codecpar; + if( inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO && + inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO && + inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE){ + stream_map[i] = -1; + continue; + } + else{ + stream_map[i] = stream_idx++ ; + outStream = avformat_new_stream(oFmtCtx, NULL); + if( !outStream ){ + av_log(oFmtCtx, AV_LOG_ERROR, "NO MEMORT!\n"); + goto _ERROR; + } + avcodec_parameters_copy(outStream->codecpar, inStream->codecpar); + outStream->codecpar->codec_tag = 0; + } + } + + + // 绑定 + ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 7.写多媒体文件头到目的文件 + + ret = avformat_write_header(oFmtCtx, NULL); + if( ret < 0 ){ + av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + goto _ERROR; + } + + // 8.从源多媒体文件中读到音频/视频/字幕数据到目的文件中 + +// 0 1 2 3 4 5 +// -1 1 -1 1 -1 1 + +// 0 1 2 3 4 5 +// -1 0 -1 1 -1 2 + + AVPacket pkt; + while( av_read_frame(pFmtCtx, &pkt) >= 0) { + AVStream *inStream, *outStream; + inStream = pFmtCtx->streams[pkt.stream_index]; + if( stream_map[pkt.stream_index] < 0 ){ + av_packet_unref(&pkt); + continue; + } + + pkt.stream_index = stream_map[pkt.stream_index]; + + outStream = oFmtCtx->streams[pkt.stream_index]; + av_packet_rescale_ts(&pkt, inStream->time_base, outStream->time_base); + // pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + // pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); + // pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base); + // pkt.stream_index = 0; + pkt.pos = -1; + av_interleaved_write_frame(oFmtCtx, &pkt); + av_packet_unref(&pkt); + } + + // 9.写多媒体文件尾到文件中 + + av_write_trailer(oFmtCtx); + + // 10.将申请的资源释放掉 + +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( oFmtCtx->pb ){ + avio_close(oFmtCtx->pb); + } + if( oFmtCtx ){ + avformat_free_context(oFmtCtx); + oFmtCtx = NULL; + } + if( stream_map ){ + av_free(stream_map); + } + return 0; +} + diff --git a/study_ffmpeg/5_/test_log b/study_ffmpeg/5_/test_log new file mode 100755 index 0000000..78c01eb Binary files /dev/null and b/study_ffmpeg/5_/test_log differ diff --git a/study_ffmpeg/5_/test_log.c b/study_ffmpeg/5_/test_log.c new file mode 100644 index 0000000..76d4e2f --- /dev/null +++ b/study_ffmpeg/5_/test_log.c @@ -0,0 +1,8 @@ +#include +#include +int main(int argc, char* argv[]){ + printf("\n__())()___\n"); + av_log_set_level(AV_LOG_DEBUG); + av_log(NULL, AV_LOG_INFO,"hello world!\n"); + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/6_/build_avdio.h264 b/study_ffmpeg/6_/build_avdio.h264 new file mode 100644 index 0000000..a2bf585 Binary files /dev/null and b/study_ffmpeg/6_/build_avdio.h264 differ diff --git a/study_ffmpeg/6_/encode_audio b/study_ffmpeg/6_/encode_audio new file mode 100755 index 0000000..089a8b1 Binary files /dev/null and b/study_ffmpeg/6_/encode_audio differ diff --git a/study_ffmpeg/6_/encode_audio.c b/study_ffmpeg/6_/encode_audio.c new file mode 100644 index 0000000..1477394 --- /dev/null +++ b/study_ffmpeg/6_/encode_audio.c @@ -0,0 +1,195 @@ +#include +#include +#include +#include + +static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt){ + const enum AVSampleFormat *p = codec->sample_fmts; + while( *p != AV_SAMPLE_FMT_NONE ){ + if( *p == sample_fmt ){ + return 1; + } + p++; + } + return 0; +} + + +static int select_best_sample_rate(const AVCodec *codec){ + const int *p; + int best_samplerate = 0; + + if( !codec->supported_samplerates){ + return 44100; + } + p = codec->supported_samplerates; + while( *p ){ + if( !best_samplerate || abs(44100 - *p )= 0 ){ + ret = avcodec_receive_packet(ctx, pkt); + if( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF ){ + return 0; + } + else if( ret < 0 ){ + return -1; + } + fwrite(pkt->data, 1, pkt->size, out); + av_packet_unref(pkt); + } + +_END: + return 0; +} + + +int main(int argc, char *argv[]) +{ + + av_log_set_level(AV_LOG_DEBUG); + // 1.输入参数 + if( argc<3 ){ + av_log(NULL, AV_LOG_ERROR, "arguments must be more than 2\n"); + goto _ERROR; + + } + char *dst = NULL; + char *codecName = NULL; + dst = argv[1]; + + + // 2.查找编码器 + const AVCodec *codec = NULL; + // codec = avcodec_find_encoder_by_name(codecName); + // avcodec_find_encoder_by_name("libfdk_acc"); // 第三方的 + codec = avcodec_find_encoder(AV_CODEC_ID_AAC); // ffmpeg内部的 + if( !codec ){ + av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s\n", codecName); + goto _ERROR; + } + + // 3.创建编码器上下文 + AVCodecContext *ctx = avcodec_alloc_context3(codec); + if( !ctx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n"); + goto _ERROR; + } + + // 4.设置编码器参数 + + ctx->bit_rate = 64000; // 一般在64k\128k\之间 + ctx->sample_fmt = AV_SAMPLE_FMT_S16; + if( !check_sample_fmt(codec, ctx->sample_fmt) ) + { + av_log(NULL, AV_LOG_ERROR, "Encoder does not support sample format!\n"); + goto _ERROR; + } + + ctx->sample_rate = select_best_sample_rate(codec); + av_channel_layout_copy(&ctx->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); + + // 5.编码器与编码器上下文绑定到一起 + + int ret; + ret = avcodec_open2(ctx, codec, NULL); + if( ret < 0 ){ + av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s\n", av_err2str(ret)); + goto _ERROR; + } + + // 6.创建输出文件 + FILE *f = fopen(dst, "wb"); + if( !f ){ + av_log(NULL, AV_LOG_ERROR, "Don't open file: %s\n", dst); + goto _ERROR; + } + + // 7.创建AVFrame (保存原始音频帧 + + AVFrame *frame = av_frame_alloc(); + if( !frame ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + frame->nb_samples = ctx->frame_size; + frame->format = ctx->sample_fmt; + av_channel_layout_copy(&frame->ch_layout, &ctx->ch_layout); + ret = av_frame_get_buffer(frame, 0); + if( ret < 0 ){ + av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame. \n"); + goto _ERROR; + } + + // 8.创建AVPacket (保存编码后的音频帧 / 一个packet中可能含有多个 + + AVPacket *pkt = av_packet_alloc(); + if( !pkt ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + + // 9.生成音频内容 + uint16_t *samples = NULL; + float t = 0 ; + float tincr = 2 * M_PI * 440 / ctx->sample_rate; + for( int i=0 ; i<200 ; i++ ){ + ret = av_frame_make_writable(frame); + if( ret < 0 ){ + av_log(NULL, AV_LOG_ERROR, "Could not allocate space!\n"); + goto _ERROR; + } + samples = (uint16_t*)frame->data[0]; + for(int j=0 ; jframe_size ; j++ ) + { + samples[2*j] = (int)(sin(t) * 10000 ); // 因为每个采样大小是两字节 + for( int k=1 ; kch_layout.nb_channels ; k++ ){ + samples[2*j+ k] = samples[2*j]; + } + t += tincr; + } + encode(ctx, NULL, pkt, f); + } + + // 10.编码 + encode(ctx, NULL, pkt, f); + +_ERROR: + // ctx + if( ctx ){ + avcodec_free_context(&ctx); + } + // // avframe + // if( frame ){ + // av_frame_free(&frame); + // } + // // avpacket + // if( pkt ){ + // av_packet_free(&pkt); + // } + // // dst + // if( f ){ + // fclose(f); + // } + + return 0; +} + diff --git a/study_ffmpeg/6_/encode_video b/study_ffmpeg/6_/encode_video new file mode 100755 index 0000000..963c153 Binary files /dev/null and b/study_ffmpeg/6_/encode_video differ diff --git a/study_ffmpeg/6_/encode_video.c b/study_ffmpeg/6_/encode_video.c new file mode 100644 index 0000000..881fa3b --- /dev/null +++ b/study_ffmpeg/6_/encode_video.c @@ -0,0 +1,180 @@ +#include +#include +#include + + +static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *out){ + int ret = -1; + + + ret = avcodec_send_frame(ctx, frame); + if( ret < 0 ) + { + av_log(NULL, AV_LOG_ERROR, "Failed to send frame to encoder!\n"); + goto _END; + } + + while( ret >= 0 ){ + ret = avcodec_receive_packet(ctx, pkt); + if( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF ){ + return 0; + } + else if( ret < 0 ){ + return -1; + } + fwrite(pkt->data, 1, pkt->size, out); + av_packet_unref(pkt); + } + +_END: + return 0; +} + + +int main(int argc, char *argv[]) +{ + + av_log_set_level(AV_LOG_DEBUG); + // 1.输入参数 + if( argc<3 ){ + av_log(NULL, AV_LOG_ERROR, "arguments must be more than 3\n"); + goto _ERROR; + + } + char *dst = NULL; + char *codecName = NULL; + dst = argv[1]; + codecName = argv[2]; + + + // 2.查找编码器 + const AVCodec *codec = NULL; + codec = avcodec_find_encoder_by_name(codecName); + if( !codec ){ + av_log(NULL, AV_LOG_ERROR, "don't find Codec: %s\n", codecName); + goto _ERROR; + } + + // 3.创建编码器上下文 + AVCodecContext *ctx = avcodec_alloc_context3(codec); + if( !ctx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n"); + goto _ERROR; + } + + // 4.设置编码器参数 + + ctx->width = 640; + ctx->height = 480; + ctx->bit_rate = 500000; // 一般在500~600之间 + + ctx->time_base = (AVRational){1, 25}; + ctx->framerate = (AVRational){25, 1}; + + ctx->gop_size = 10; + ctx->max_b_frames = 1; // 一般情况下不超过三帧 + ctx->pix_fmt = AV_PIX_FMT_YUV420P; + + if( codec->id == AV_CODEC_ID_H264 ){ // 设置私有属性 + av_opt_set(ctx->priv_data, "preset", "slow", 0); + } + + // 5.编码器与编码器上下文绑定到一起 + + int ret; + ret = avcodec_open2(ctx, codec, NULL); + if( ret < 0 ){ + av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s\n", av_err2str(ret)); + goto _ERROR; + } + + // 6.创建输出文件 + FILE *f = fopen(dst, "wb"); + if( !f ){ + av_log(NULL, AV_LOG_ERROR, "Don't open file: %s\n", dst); + goto _ERROR; + } + + // 7.创建AVFrame (保存原始音频帧 + + AVFrame *frame = av_frame_alloc(); + if( !frame ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + frame->width = ctx->width; + frame->height = ctx->height; + frame->format = ctx->pix_fmt; + ret = av_frame_get_buffer(frame, 0); + if( ret < 0 ){ + av_log(NULL, AV_LOG_ERROR, "Could not allocate the video frame. \n"); + goto _ERROR; + } + + // 8.创建AVPacket (保存编码后的音频帧 / 一个packet中可能含有多个 + + AVPacket *pkt = av_packet_alloc(); + if( !pkt ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + + // 9.生成视频内容 + for( int i=0 ; i<25 ; i++ ){ + ret =av_frame_make_writable(frame); + if( ret < 0 ){ + break; + } + + // Y分量 + for( int y=0 ; yheight ; y++ ){ + for( int x=0 ; xwidth ; x++ ){ + frame->data[0][y*frame->linesize[0] + x] = x + y + i * 3; + } + } + + // UV分量 + for( int y=0 ; yheight/2 ; y++ ){ + for( int x=0 ; xwidth/2 ; x++ ){ + frame->data[1][y*frame->linesize[1] + x] = 128 + y + i * 2; + frame->data[2][y*frame->linesize[2] + x] = 64 + x + i * 5; + } + } + + frame->pts = i; + + + + // 10.编码 + ret = encode(ctx, frame, pkt, f); + if( ret == -1 ){ + goto _ERROR; + } + } + + // 10.编码 + encode(ctx, NULL, pkt, f); + +_ERROR: + // ctx + if( ctx ){ + avcodec_free_context(&ctx); + } + // // avframe + // if( frame ){ + // av_frame_free(&frame); + // } + // // avpacket + // if( pkt ){ + // av_packet_free(&pkt); + // } + // // dst + // if( f ){ + // fclose(f); + // } + + return 0; +} + diff --git a/study_ffmpeg/6_/gen_pic b/study_ffmpeg/6_/gen_pic new file mode 100755 index 0000000..b1453a1 Binary files /dev/null and b/study_ffmpeg/6_/gen_pic differ diff --git a/study_ffmpeg/6_/gen_pic.c b/study_ffmpeg/6_/gen_pic.c new file mode 100644 index 0000000..77b5cff --- /dev/null +++ b/study_ffmpeg/6_/gen_pic.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include + +static void savePic(unsigned char *buf, int linesize, int width, int height, char *name){ + FILE *f; + f = fopen(name, "wb"); + fprintf(f, "P5\n%d %d\n%d\n", width, height, 255); + for( int i=0 ; i= 0 ){ + ret = avcodec_receive_frame(ctx, frame); + if( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF ){ + return 0; + } + else if( ret < 0 ){ + return -1; + } + snprintf(buf, sizeof(buf), "%s-%ld", out, ctx->frame_num); + savePic(frame->data[0], + frame->linesize[0], + frame->width, + frame->height, + buf + ); + if( pkt ){ + av_packet_unref(pkt); + } + } + +_END: + return 0; +} + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + + struct SwsContext *swsCtx = NULL; + + av_log_set_level(AV_LOG_DEBUG); + if( argc < 3 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 3.从多媒体文件中找到视频流 + + int idx = -1; + idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if( idx < 0 ){ + av_log(pFmtCtx, AV_LOG_ERROR, "Dose not include audio stream!\n"); + goto _ERROR; + } + + AVStream *inStream = NULL; + inStream = pFmtCtx->streams[idx]; + + // 4.查找解码器 + const AVCodec *codec = NULL; + codec = avcodec_find_decoder(inStream->codecpar->codec_id); + if( !codec ){ + av_log(NULL, AV_LOG_ERROR, "Could not find libx264 Codec\n"); + goto _ERROR; + } + + // 5.创建解码器上下文 + AVCodecContext *ctx = NULL; + ctx = avcodec_alloc_context3(codec); + if( !ctx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n"); + goto _ERROR; + } + avcodec_parameters_to_context(ctx, inStream->codecpar); + + + // 6.解码器与解码器上下文绑定到一起 + ret = avcodec_open2(ctx, codec, NULL); + if( ret < 0 ){ + av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s\n", av_err2str(ret)); + goto _ERROR; + } + + // 7.创建AVFrame (保存原始音频帧 + + AVFrame *frame = NULL; + frame = av_frame_alloc(); + if( !frame ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + // 8.创建AVPacket (保存编码后的音频帧 / 一个packet中可能含有多个 + + AVPacket *pkt = NULL; + pkt = av_packet_alloc(); + if( !pkt ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + // 9.从源多媒体文件中读到视频数据到目的文件中 + + while( av_read_frame(pFmtCtx, pkt) >= 0) { + if( pkt->stream_index == idx ){ + decode(ctx, frame, pkt, dst); + } + } + decode(ctx, frame, NULL, dst); + + // 10.将申请的资源释放掉 +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( ctx ){ + avcodec_free_context(&ctx); + ctx = NULL; + } + if( frame ){ + av_frame_free(&frame); + frame = NULL; + } + if( pkt ){ + av_packet_free(&pkt); + pkt = NULL; + } + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/6_/gen_pic_rgb b/study_ffmpeg/6_/gen_pic_rgb new file mode 100755 index 0000000..1cc21b1 Binary files /dev/null and b/study_ffmpeg/6_/gen_pic_rgb differ diff --git a/study_ffmpeg/6_/gen_pic_rgb.c b/study_ffmpeg/6_/gen_pic_rgb.c new file mode 100644 index 0000000..07ab530 --- /dev/null +++ b/study_ffmpeg/6_/gen_pic_rgb.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include + +#define WORD uint16_t +#define DWORD uint32_t +#define LONG int32_t + +static void savePic(unsigned char *buf, int linesize, int width, int height, char *name){ + FILE *f; + f = fopen(name, "wb"); + fprintf(f, "P5\n%d %d\n%d\n", width, height, 255); + for( int i=0 ; iwidth = width; + frameBGR->height = height; + frameBGR->format = AV_PIX_FMT_BGR24; + + av_frame_get_buffer(frameBGR, 0); + + sws_scale(swsCtx, (const uint8_t * const *)frame->data, frame->linesize, 0, frame->height, frameBGR->data, frameBGR->linesize); + + // 2.BITMAPINFOHEADER + BITMAPINFOHEADER infoHeader; + infoHeader.biSize = sizeof(BITMAPINFOHEADER); + infoHeader.biWidth = width ; + infoHeader.biHeight = height * (-1); // 因为坐标正好与我们正常坐标相反 + infoHeader.biCompression = 0; + infoHeader.biSizeImage = 0; + infoHeader.biClrImportant = 0; + infoHeader.biClrUsed = 0; + infoHeader.biXPelsPerMeter = 0; + infoHeader.biYPelsPerMeter = 0; + infoHeader.biPlanes = 0; + + // 3.BITMAPFILEHEADER + int datasize = width * height * 3; + + BITMAPFILEHEADER fileHeader; + fileHeader.bfType = 0x4d42 ; // "BM" + fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datasize; + fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + // 4.将数据写到文件中 + FILE *f = NULL; + f = fopen(name, "wb"); + fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, f); + fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, f); + fwrite(frame->data[0], 1, datasize, f); + + // 5.释放资源 + fclose(f); + av_freep(&frameBGR->data[0]); + av_free(frameBGR); + + +} + +static int decode(AVCodecContext *ctx, struct SwsContext *swsCtx, AVFrame *frame, AVPacket *pkt, char *out){ + + int ret = -1; + + ret = avcodec_send_packet(ctx, pkt); + if( ret < 0 ) + { + av_log(NULL, AV_LOG_ERROR, "Failed to send frame to decoder!\n"); + goto _END; + } + + char buf[1024]; + while( ret >= 0 ){ + ret = avcodec_receive_frame(ctx, frame); + if( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF ){ + return 0; + } + else if( ret < 0 ){ + return -1; + } + snprintf(buf, sizeof(buf), "%s-%ld", out, ctx->frame_num); + /* + savePic(frame->data[0], + frame->linesize[0], + frame->width, + frame->height, + buf); + */ + saveBMP(swsCtx, frame, frame->width, frame->height, buf); + if( pkt ){ + av_packet_unref(pkt); + } + } + +_END: + return 0; +} + +int main(int argc, char* argv[]) +{ + // 1.处理一些参数; + int ret = -1; + char* src; + char* dst; + + struct SwsContext *swsCtx = NULL; + + av_log_set_level(AV_LOG_DEBUG); + if( argc < 3 ) { + av_log(NULL, AV_LOG_INFO, "arguments must be more than 3\n"); + exit(-1); + } + + src = argv[1]; + dst = argv[2]; + + // 2.打开多媒体文件; + + AVFormatContext *pFmtCtx = NULL; + if( (ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0 ){ + av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret)); + exit(-1); + } + + // 3.从多媒体文件中找到视频流 + + int idx = -1; + idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if( idx < 0 ){ + av_log(pFmtCtx, AV_LOG_ERROR, "Dose not include audio stream!\n"); + goto _ERROR; + } + + AVStream *inStream = NULL; + inStream = pFmtCtx->streams[idx]; + + // 4.查找解码器 + const AVCodec *codec = NULL; + codec = avcodec_find_decoder(inStream->codecpar->codec_id); + if( !codec ){ + av_log(NULL, AV_LOG_ERROR, "Could not find libx264 Codec\n"); + goto _ERROR; + } + + // 5.创建解码器上下文 + AVCodecContext *ctx = NULL; + ctx = avcodec_alloc_context3(codec); + if( !ctx ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMRORY\n"); + goto _ERROR; + } + avcodec_parameters_to_context(ctx, inStream->codecpar); + + + // 6.解码器与解码器上下文绑定到一起 + ret = avcodec_open2(ctx, codec, NULL); + if( ret < 0 ){ + av_log(ctx, AV_LOG_ERROR, "Don't open codec: %s\n", av_err2str(ret)); + goto _ERROR; + } + + // 6.1获得SWS上下文 + swsCtx = sws_getContext(ctx->width, ctx->height, AV_PIX_FMT_YUV420P, // src的 + 640, 360, AV_PIX_FMT_BGR24, // dst的 + SWS_BICUBIC, NULL, NULL, NULL); + + // 7.创建AVFrame (保存原始音频帧 + + AVFrame *frame = NULL; + frame = av_frame_alloc(); + if( !frame ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + // 8.创建AVPacket (保存编码后的音频帧 / 一个packet中可能含有多个 + + AVPacket *pkt = NULL; + pkt = av_packet_alloc(); + if( !pkt ){ + av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n"); + goto _ERROR; + } + + // 9.从源多媒体文件中读到视频数据到目的文件中 + + while( av_read_frame(pFmtCtx, pkt) >= 0) { + if( pkt->stream_index == idx ){ + decode(ctx, swsCtx, frame, pkt, dst); + } + } + decode(ctx, swsCtx, frame, NULL, dst); + + // 10.将申请的资源释放掉 +_ERROR: + if( pFmtCtx ){ + avformat_close_input(&pFmtCtx); + pFmtCtx = NULL; + } + if( ctx ){ + avcodec_free_context(&ctx); + ctx = NULL; + } + if( frame ){ + av_frame_free(&frame); + frame = NULL; + } + if( pkt ){ + av_packet_free(&pkt); + pkt = NULL; + } + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/7_/SDL_Event b/study_ffmpeg/7_/SDL_Event new file mode 100755 index 0000000..9718c22 Binary files /dev/null and b/study_ffmpeg/7_/SDL_Event differ diff --git a/study_ffmpeg/7_/SDL_Event.c b/study_ffmpeg/7_/SDL_Event.c new file mode 100644 index 0000000..3ab2f57 --- /dev/null +++ b/study_ffmpeg/7_/SDL_Event.c @@ -0,0 +1,97 @@ +#include +#include + +int main(int argc, char* argv[]) +{ + int quit = 1; + + + + + + SDL_Init(SDL_INIT_VIDEO); + + + SDL_Window* window = NULL; + window = SDL_CreateWindow("SDL2 Window", + 200, // 窗口初始位置x + 200, // 窗口初始位置y + 640, // 窗口宽度 + 480, // 窗口高度 + SDL_WINDOW_SHOWN + ); + if (!window) { + printf("Failed to create window."); + goto __EXIT; + } + + + SDL_Renderer* render = NULL; + render = SDL_CreateRenderer(window, -1, 0); + if (!render) { + SDL_Log("Failed to create render."); + goto __DWINDOW; + } + +/* + SDL_SetRenderDrawColor(render, 255, 0, 0, 255); + + SDL_RenderClear(render); + + SDL_RenderPresent(render); + */ + + SDL_Texture* texture = NULL; + texture = SDL_CreateTexture(render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 600, 480); + if (!texture) { + SDL_Log("Failed to create texture!"); + goto __RENDER; + } + + + + SDL_Event event; + SDL_Rect rect; + rect.w = 30; + rect.h = 30; + do { + // SDL_WaitEvent(&event); 没有事件的时候,代码会阻塞在这里,等待事件。 + SDL_PollEvent(&event); + switch(event.type) { + case SDL_QUIT: + quit = 0; + break; + default: + SDL_Log("event type is: %d", event.type); + } + + + rect.x = rand() % 600; + rect.y = rand() % 480; + + SDL_SetRenderTarget(render, texture); + SDL_SetRenderDrawColor(render, 0, 0, 0, 0); + SDL_RenderClear(render); + + SDL_RenderDrawRect(render, &rect); + SDL_SetRenderDrawColor(render, 255, 0, 0, 0); + SDL_RenderFillRect(render, &rect); // 方块是特殊的,不是完整的,不能用SDL_RenderClear + + SDL_SetRenderTarget(render, NULL); // 恢复成默认的渲染目标 + SDL_RenderCopy(render, texture, NULL, NULL); + + SDL_RenderPresent(render); + } while(quit); + + SDL_DestroyTexture(texture); + +__RENDER: + SDL_DestroyRenderer(render); + +__DWINDOW: + SDL_DestroyWindow(window); + +__EXIT: + SDL_Quit(); + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/7_/SDL_PCM.c b/study_ffmpeg/7_/SDL_PCM.c new file mode 100644 index 0000000..5c0e70d --- /dev/null +++ b/study_ffmpeg/7_/SDL_PCM.c @@ -0,0 +1,88 @@ +#include +#include + +#define BLOCK_SIZE 4096000 + +static size_t buffer_len = 0; +static Uint8* audio_buf = NULL; +static Uint8* audio_pos = NULL; + +// udata 是 spec.userdata。 stream 是声卡的缓冲区指针。len 是声卡缓冲区的长度。 +void read_audio_data(void* udata, Uint8* stream, int len) +{ + if (0 == buffer_len) { + return; + } + + SDL_memset(stream, 0, len); + + len = (len < buffer_len) ? len : buffer_len; + SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME); + + audio_pos += len; + buffer_len -= len; +} + +int main(int argc, char* argv[]) +{ + int ret = -1; + char* path = "./1.pcm"; + FILE* audio_fd = NULL; + + if (SDL_Init(SDL_INIT_AUDIO)) { + SDL_Log("Failed to initial!"); + return ret; + } + + audio_fd = fopen(path, "r"); + if (!audio_fd) { + SDL_Log("Failed to open pcm file!"); + goto __FAIL; + } + + audio_buf = (Uint8*)malloc(BLOCK_SIZE); + if (!audio_buf) { + SDL_Log("Failed to alloc memory"); + goto __FAIL; + } + + SDL_AudioSpec spec; + spec.freq = 44100; + spec.channels = 2; + spec.format = AUDIO_S16SYS; + spec.silence = 0; + spec.callback = read_audio_data; + spec.userdata = NULL; + + if(SDL_OpenAudio(&spec, NULL)) { + SDL_Log("Failed to open audio device!"); + goto __FAIL; + } + + SDL_PauseAudio(0); + + do { + buffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd); + audio_pos = audio_buf; + while (audio_pos < (audio_buf + buffer_len)) { + SDL_Delay(1); + } + } while(buffer_len != 0); + + SDL_CloseAudio(); + + ret = 0; + +__FAIL: + if (audio_buf) { + free(audio_buf); + } + + if (audio_fd) { + fclose(audio_fd); + } + + SDL_Quit(); + + return 0; +} \ No newline at end of file diff --git a/study_ffmpeg/7_/first_sdl b/study_ffmpeg/7_/first_sdl new file mode 100755 index 0000000..c443fa2 Binary files /dev/null and b/study_ffmpeg/7_/first_sdl differ diff --git a/study_ffmpeg/7_/first_sdl.c b/study_ffmpeg/7_/first_sdl.c new file mode 100644 index 0000000..86af19d --- /dev/null +++ b/study_ffmpeg/7_/first_sdl.c @@ -0,0 +1,39 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + SDL_Window *window = NULL; + + SDL_Init(SDL_INIT_VIDEO); + + window = SDL_CreateWindow("SDL2 Window", 200, 200, 640, 480, SDL_WINDOW_SHOWN); + + if( !window ){ + printf("Failed to Create window!\n"); + goto __EXIT; + } + + SDL_Renderer *render = NULL; + render = SDL_CreateRenderer(window, -1, 0); + + if( !render ){ + SDL_Log("Failed ot Create Render!"); + goto __DWINDOWN; + } + + SDL_SetRenderDrawColor(render, 255, 0, 0, 255); + + SDL_RenderClear(render); + + SDL_RenderPresent(render); + + SDL_Delay(30000); + +__DWINDOWN: + SDL_DestroyWindow(window); + +__EXIT: + SDL_Quit(); + return 0; +} diff --git a/study_ffmpeg/8_/simpleplayer.c b/study_ffmpeg/8_/simpleplayer.c new file mode 100644 index 0000000..9cf755a --- /dev/null +++ b/study_ffmpeg/8_/simpleplayer.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +int main() +{ + +} \ No newline at end of file