-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.cpp
executable file
·136 lines (104 loc) · 3.68 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <iostream>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/error.h"
#include "libavutil/time.h"
}
using namespace std;
//#define IN_FILE_NAME "rtmp://202.69.69.180:443/webcast/bshdlive-pc"
#define IN_FILE_NAME "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"
#define OUT_URL "cuc_ieschool.avi"
int err;
char buf[1024] = { 0 };
#define ptr_check(x) \
do {\
if (!x){\
printf("operator fail"); \
return -1; \
}\
}while(0)
#define void_handle(x) \
if ((err = (x)) < 0) {\
memset(buf, 0, 1024); \
av_strerror(err, buf, 1024); \
printf(buf); \
return -1; \
}
#define ret_handle(x, r) \
if ((r = (x)) < 0) {\
memset(buf, 0, 1024); \
av_strerror(r, buf, 1024); \
printf(buf); \
return -1; \
}
int main()
{
AVFormatContext *in_ctx = NULL, *out_ctx = NULL;
AVDictionary* options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", 0);
void_handle(avformat_open_input(&in_ctx, IN_FILE_NAME, NULL, &options));
av_usleep(100000);
void_handle(avformat_find_stream_info(in_ctx, NULL));
void_handle(avformat_alloc_output_context2(&out_ctx, NULL, "flv", OUT_URL));
//查找流索引
int vedio_index = -1, audio_index = -1;
ret_handle(av_find_best_stream(in_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0), vedio_index);
ret_handle(av_find_best_stream(in_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0), audio_index);
//创建输出流
for (int i = 0; i < in_ctx->nb_streams; ++i) {
AVStream *in_stream = in_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(out_ctx, in_stream->codec->codec);
void_handle(avcodec_parameters_to_context(out_stream->codec, in_stream->codecpar));
out_stream->codec->codec_tag = 0;
if (out_stream->codec->flags & AVFMT_GLOBALHEADER) {
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
//是否需要打开输出文件
if (!(out_ctx->oformat->flags & AVFMT_NOFILE)) {
void_handle(avio_open(&out_ctx->pb, OUT_URL, AVIO_FLAG_READ_WRITE));
}
//写文件头
void_handle(avformat_write_header(out_ctx, NULL));
int64_t start = av_gettime();
AVPacket *packet = av_packet_alloc();
int index = 0;
//推流
while (1) {
//读取一帧原始数据
if (av_read_frame(in_ctx, packet) < 0) break;
//pkt时间转换成ffmpeg系统时间,如果还未到显示时间,则等待显示时间
AVRational ffmpeg_time_base = { 1, AV_TIME_BASE };
int64_t pkt_time = av_rescale_q(packet->pts, in_ctx->streams[vedio_index]->time_base, ffmpeg_time_base);
if (packet->stream_index == vedio_index) {
int64_t nowTime = av_gettime() - start;
if (pkt_time > nowTime) {
// av_usleep(pkt_time - nowTime);
}
}
//转换时间基
av_packet_rescale_ts(packet,
in_ctx->streams[packet->stream_index]->time_base,
out_ctx->streams[packet->stream_index]->time_base);
if (packet->dts < out_ctx->streams[packet->stream_index]->cur_dts) {
printf("当前帧dts小于上一帧 %lld < %lld\n", packet->dts, in_ctx->streams[packet->stream_index]->cur_dts);
continue;
}
if (packet->stream_index == vedio_index) {
printf("packet->pts = %lld, ", packet->pts); //
printf("index = %d, packet->dts = %lld, cur_dts = %lld\n", index++, packet->dts, out_ctx->streams[packet->stream_index]->cur_dts);
}
//音视频分开
(av_interleaved_write_frame(out_ctx, packet));
av_packet_unref(packet);
}
//写文件尾
void_handle(av_write_trailer(out_ctx));
avformat_close_input(&in_ctx);
avformat_free_context(out_ctx);
av_packet_free(&packet);
cout << "over";
getchar();
return 0;
}