-
Notifications
You must be signed in to change notification settings - Fork 11
IJKMediaPlay项目新增API说明
Richard Liu edited this page Mar 20, 2017
·
4 revisions
IJKMediaPlayback
IJKMediaPlayback是暴露给第三方使用的类,在此类中添加了:
/**
- 录制视频(只能录制RTSP流)格式mov
- @param streamURL 流地址
- @param filePath 录制的视频存储的路径
- @param bStop 是否开始录制(NO开始, YES结束)
- @return int 返回-1,录制失败, 0为正常 */
-
(int)rtsp2mov:(NSString *)streamURL storageFilePath:(NSString *)filePath isStop:(BOOL)bStop { // 输入 AVStream *i_video_stream = NULL; //视频 AVStream *i_audio_stream = NULL; //音频 AVFormatContext *i_fmt_ctx = NULL;
// 输出 AVStream *o_video_stream = NULL; //视频 AVStream *o_audio_stream = NULL; //音频 AVFormatContext *o_fmt_ctx = NULL;
// ijkmp_global_init(); // // FFMPEG注册 // ijkav_register_all(); // avcodec_register_all(); // av_register_all(); // if(avformat_network_init() != 0){ // printf("avformat_network_init() 失败 \n"); // return -1; // }
// 视频存储的路径
const char *filename = [filePath cStringUsingEncoding:NSUTF8StringEncoding];
// 打开网络流或文件流
if (avformat_open_input(&i_fmt_ctx, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], NULL, NULL)!=0)
{
printf("无法打开输入流.\n");
return -1;
}
if (avformat_find_stream_info(i_fmt_ctx, NULL)<0)
{
printf("找不到流信息.\n");
return -1;
}
// 列出输入文件的相关流信息
printf("---------------- 输入文件信息 ---------------\n");
av_dump_format(i_fmt_ctx, 0, [streamURL cStringUsingEncoding:NSUTF8StringEncoding], 0);
printf("-------------------------------------------------\n");
/* find first video stream */
for (unsigned i=0; i<i_fmt_ctx->nb_streams; i++)
{
if (i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// 视频
i_video_stream = i_fmt_ctx->streams[i];
}
else if(i_fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
// 音频
i_audio_stream = i_fmt_ctx->streams[i];
}
}
if (i_video_stream == NULL)
{
fprintf(stderr, "没有找到任何视频流媒体\n");
return -1;
}
AVOutputFormat *oformat = av_guess_format(NULL, filename, NULL);
/**
* avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename)
*
* ctx: 函数调用成功之后创建的AVFormatContext结构体
* oformat: 指定AVFormatContext中的AVOutputFormat,用于确定输出格式。如果指定为NULL,可以设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式
* format_name: 指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等
* filename: 指定输出文件的名称
*/
if(avformat_alloc_output_context2(&o_fmt_ctx, oformat, NULL, filename) !=0){
fprintf(stderr, "初始化o_fmt_ctx结构体失败\n");
return -1;
}
/**************************************** 视频 **********************************/
o_video_stream = avformat_new_stream(o_fmt_ctx, NULL);
{
if (o_video_stream == NULL){
printf("没有获取到视频流信息.\n");
return -1;
}
AVCodecParameters *oVcc;
oVcc = o_video_stream->codecpar;
//平均比特率
oVcc->bit_rate = 400000;
oVcc->codec_id = i_video_stream->codecpar->codec_id;
oVcc->codec_type = i_video_stream->codecpar->codec_type;
oVcc->sample_aspect_ratio.num = i_video_stream->sample_aspect_ratio.num;
oVcc->sample_aspect_ratio.den = i_video_stream->sample_aspect_ratio.den;
oVcc->extradata = i_video_stream->codecpar->extradata;
oVcc->extradata_size = i_video_stream->codecpar->extradata_size;
oVcc->width = i_video_stream->codecpar->width;
oVcc->height = i_video_stream->codecpar->height;
oVcc->format = i_video_stream->codecpar->format;
//帧率
o_video_stream->r_frame_rate = i_video_stream->r_frame_rate;
}
/**************************************** 音频 **********************************/
o_audio_stream = avformat_new_stream(o_fmt_ctx, NULL);
{
if (o_audio_stream == NULL){
printf("没有获取到音频流信息.\n");
return -1;
}
AVCodecParameters *oAcc;
oAcc = o_audio_stream->codecpar;
oAcc->codec_id = AV_CODEC_ID_AAC; //AAC格式
oAcc->codec_type = AVMEDIA_TYPE_AUDIO;
oAcc->bit_rate = 64000;
//采样率(音频)
oAcc->sample_rate = 44100;
//声道数(音频)
oAcc->channel_layout = AV_CH_LAYOUT_STEREO;
oAcc->channels = av_get_channel_layout_nb_channels(oAcc->channel_layout);
}
/*******************************************************************************/
// 列出输出文件的相关流信息
printf("------------------- 输出文件信息 ------------------\n");
av_dump_format(o_fmt_ctx, 0, filename, 1);
printf("-------------------------------------------------\n");
avio_open(&o_fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
if (!(o_fmt_ctx->flags & AVFMT_NOFILE)) {
}
if (!o_fmt_ctx->nb_streams) {
fprintf(stderr, "output file dose not contain any stream\n");
return -1;
}
// 根据文件名的后缀写相应格式的文件头
if (avformat_write_header(o_fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not write header for output file\n");
return -1;
}
int last_pts = 0, last_dts = 0;
int au_pts = 0, au_dts = 0;
int64_t pts = 0, dts = 0;
int64_t a_pts = 0, a_dts = 0;
int64_t end_time = 0;
while (!bStop)
{
end_time++;
AVPacket i_pkt;
av_init_packet(&i_pkt);
i_pkt.size = 0;
i_pkt.data = NULL;
// 获取流中每一帧的数据流(包)
if (av_read_frame(i_fmt_ctx, &i_pkt) < 0 )
break;
/*
* pts and dts should increase monotonically
* pts should be >= dts
*/
if (i_pkt.stream_index == AVMEDIA_TYPE_VIDEO)
{
i_pkt.flags |= AV_PKT_FLAG_KEY;
pts = i_pkt.pts;
i_pkt.pts += last_pts;
dts = i_pkt.dts;
i_pkt.dts += last_dts;
i_pkt.stream_index = 0;
printf("%lld %lld\n", i_pkt.pts, i_pkt.dts);
static int num = 1;
printf("frame %d\n", num++);
// 往输出流中写一个分包
av_interleaved_write_frame(o_fmt_ctx, &i_pkt);
}
else if (i_pkt.stream_index == AVMEDIA_TYPE_AUDIO){
i_pkt.flags |= AV_PKT_FLAG_KEY;
a_pts = i_pkt.pts;
i_pkt.pts += au_pts;
a_dts = i_pkt.dts;
i_pkt.dts += au_dts;
i_pkt.stream_index = 1;
printf("%lld %lld\n", i_pkt.pts, i_pkt.dts);
static int num = 1;
printf("frame %d\n", num++);
// 往输出流中写一个分包
av_interleaved_write_frame(o_fmt_ctx, &i_pkt);
}
if (end_time == 2000)
{
bStop = YES;
}
}
last_dts += dts;
last_pts += pts;
au_dts += a_dts;
au_pts += a_pts;
avformat_close_input(&i_fmt_ctx);
// 写输出流(文件)的文件尾
av_write_trailer(o_fmt_ctx);
// 视频信息
av_freep(&o_fmt_ctx->streams[0]->codecpar);
av_freep(&o_fmt_ctx->streams[0]);
// 音频信息
av_freep(&o_fmt_ctx->streams[1]->codecpar);
av_freep(&o_fmt_ctx->streams[1]);
avio_close(o_fmt_ctx->pb);
av_free(o_fmt_ctx);
return 0;
}