Skip to content

Commit 58530d1

Browse files
committed
linux demo basically works
1 parent f2ec5a3 commit 58530d1

File tree

7 files changed

+166
-142
lines changed

7 files changed

+166
-142
lines changed

example/common/cpp/libKmpWebrtc.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ struct PCClientFactoryConfig* DefaultPCClientFactoryConfig() {
3939
config->video_capture_height = 720;
4040
config->video_capture_fps = 30;
4141
config->private_config.hwnd = nullptr;
42+
config->private_config.disable_encryption = 0;
43+
config->private_config.dummy_audio_device = 0;
44+
config->private_config.transit_video = 0;
45+
config->private_config.capture_file_path = "";
46+
config->private_config.capture_dump_path = "";
4247
return config;
4348
}
4449

@@ -59,7 +64,7 @@ void* CreatePCClientFactory(struct PCClientFactoryConfig* config, PCClientFactor
5964
#if defined(WEBRTC_WIN)
6065
KType(WinPrivateConfig) private_config = KFunc(WinPrivateConfig.WinPrivateConfig)(config->private_config.hwnd, config->private_config.disable_encryption);
6166
#else
62-
KType(LinuxPrivateConfig) private_config = KFunc(LinuxPrivateConfig.LinuxPrivateConfig)(config->private_config.hwnd, config->private_config.disable_encryption, config->private_config.capture_file_path);
67+
KType(LinuxPrivateConfig) private_config = KFunc(LinuxPrivateConfig.LinuxPrivateConfig)(config->private_config.hwnd, config->private_config.disable_encryption, config->private_config.dummy_audio_device, config->private_config.transit_video, config->private_config.capture_file_path, config->private_config.capture_dump_path);
6368
#endif
6469
KType(PeerConnectionClientFactory_Config) k_config_with_pri = KFunc(utils.createPcClientFactoryConfig)(k_config, private_config);
6570

example/common/cpp/libKmpWebrtc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ enum KmpWebRTCError {
5959
struct PCClientFactoryPrivateConfig {
6060
void* hwnd;
6161
int disable_encryption;
62+
int dummy_audio_device;
63+
int transit_video;
6264
const char* capture_file_path;
65+
const char* capture_dump_path;
6366
};
6467

6568
struct PCClientFactoryConfig {

example/linuxApp/CMakeLists.txt

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ project(linuxApp)
44
set(CMAKE_CXX_STANDARD 11)
55
set(CMAKE_CXX_STANDARD_REQUIRED True)
66

7-
#find_package(Qt5 REQUIRED COMPONENTS Widgets)
8-
9-
#include_directories(${Qt5Widgets_INCLUDE_DIRS})
10-
11-
#set(CMAKE_AUTOMOC ON)
12-
#set(CMAKE_AUTORCC ON)
13-
#set(CMAKE_AUTOUIC ON)
14-
157
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libs/linux/x64)
168
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libs/windows_linux/include)
179
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../common/cpp)
@@ -23,18 +15,30 @@ file(GLOB deps
2315
${CMAKE_CURRENT_SOURCE_DIR}/../../libs/linux/x64/liblinux_pc_client.so
2416
)
2517

26-
#add_executable(${PROJECT_NAME}
27-
# main.cpp
28-
# main_window.cpp
29-
# main_window.h
30-
# loopback.cpp
31-
# ${CMAKE_CURRENT_SOURCE_DIR}/../common/cpp/libKmpWebrtc.cpp
32-
# )
18+
set(BUILD_QT_DEMO FALSE)
19+
if (BUILD_QT_DEMO)
20+
find_package(Qt5 REQUIRED COMPONENTS Widgets)
21+
22+
include_directories(${Qt5Widgets_INCLUDE_DIRS})
23+
24+
set(CMAKE_AUTOMOC ON)
25+
set(CMAKE_AUTORCC ON)
26+
set(CMAKE_AUTOUIC ON)
27+
28+
add_executable(${PROJECT_NAME}
29+
main.cpp
30+
main_window.cpp
31+
main_window.h
32+
loopback.cpp
33+
${CMAKE_CURRENT_SOURCE_DIR}/../common/cpp/libKmpWebrtc.cpp
34+
)
35+
36+
target_link_libraries(${PROJECT_NAME}
37+
${Qt5Widgets_LIBRARIES}
38+
${deps}
39+
)
40+
endif()
3341

34-
#target_link_libraries(${PROJECT_NAME}
35-
# ${Qt5Widgets_LIBRARIES}
36-
# ${deps}
37-
# )
3842

3943
add_executable(loopback
4044
console_app.cpp
@@ -46,16 +50,19 @@ target_link_libraries(loopback
4650
${deps}
4751
)
4852

49-
set(FFMPEG_INCLUDE_DIR /home/linker/src/FFmpeg/build/include)
50-
set(FFMPEG_LIB_DIR /home/linker/src/FFmpeg/build/lib)
51-
include_directories(${FFMPEG_INCLUDE_DIR})
53+
set(BUILD_FFMPEG_TEST FALSE)
54+
if (BUILD_FFMPEG_TEST)
55+
set(FFMPEG_INCLUDE_DIR /home/linker/src/FFmpeg/build/include)
56+
set(FFMPEG_LIB_DIR /home/linker/src/FFmpeg/build/lib)
57+
include_directories(${FFMPEG_INCLUDE_DIR})
5258

53-
add_executable(ffmpeg_test
54-
ffmpeg_test.cpp
55-
)
59+
add_executable(ffmpeg_test
60+
ffmpeg_test.cpp
61+
)
5662

57-
target_link_libraries(ffmpeg_test
58-
${FFMPEG_LIB_DIR}/libavcodec.so
59-
${FFMPEG_LIB_DIR}/libavformat.so
60-
${FFMPEG_LIB_DIR}/libavutil.so
61-
)
63+
target_link_libraries(ffmpeg_test
64+
${FFMPEG_LIB_DIR}/libavcodec.so
65+
${FFMPEG_LIB_DIR}/libavformat.so
66+
${FFMPEG_LIB_DIR}/libavutil.so
67+
)
68+
endif ()

example/linuxApp/console_app.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ int main(int argc, char *argv[]) {
1818
}
1919

2020
signal(SIGINT, signal_handler);
21-
loopback(argv[1]);
21+
startLoopback(argv[1]);
2222
while (running) {
2323
sleep(100);
2424
}
25+
stopLoopback();
2526
return 0;
2627
}

example/linuxApp/ffmpeg_test.cpp

Lines changed: 105 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -2,133 +2,130 @@
22

33
extern "C" {
44
#include <libavformat/avformat.h>
5+
#include <libavcodec/avcodec.h>
6+
#include <libavcodec/bsf.h>
57
#include <libavutil/timestamp.h>
68
}
79

8-
#include <iostream>
9-
#include <unistd.h>
10+
#include <stdio.h>
1011

11-
int main(int argc, char* argv[]) {
12-
if (argc < 2) {
13-
std::cerr << "Usage: " << argv[0] << " <video_file>" << std::endl;
12+
int main(int argc, char *argv[]) {
13+
AVFormatContext *fmt_ctx = NULL;
14+
AVBSFContext *bsf_ctx = NULL;
15+
FILE *outfile = NULL;
16+
int video_stream_index = -1;
17+
int ret;
18+
19+
if (argc != 3) {
20+
fprintf(stderr, "Usage: %s <input.mp4> <output.h264>\n", argv[0]);
1421
return 1;
1522
}
1623

17-
const char* input_file = argv[1];
18-
AVPacket* packet = av_packet_alloc();
19-
if (!packet) {
20-
std::cerr << "FileCapturer::Start av_packet_alloc fail";
21-
return -1;
22-
}
23-
av_init_packet(packet);
24-
25-
AVFormatContext* format_context = nullptr;
26-
int error =
27-
avformat_open_input(&format_context, input_file, nullptr, nullptr);
28-
if (error < 0) {
29-
std::cerr << "FileCapturer::Start avformat_open_input fail "
30-
<< input_file << " " << error;//av_err2str(error);
31-
av_packet_free(&packet);
32-
return -2;
33-
}
24+
const char *input_file = argv[1];
25+
const char *output_file = argv[2];
3426

35-
error = avformat_find_stream_info(format_context, nullptr);
36-
if (error < 0) {
37-
std::cerr << "FileCapturer::Start avformat_find_stream_info fail "
38-
<< error;//av_err2str(error);
39-
av_packet_free(&packet);
40-
avformat_close_input(&format_context);
41-
return -3;
27+
// 打开输入文件
28+
if ((ret = avformat_open_input(&fmt_ctx, input_file, NULL, NULL))) {
29+
fprintf(stderr, "无法打开输入文件\n");
30+
return ret;
4231
}
4332

44-
int v_stream_no = av_find_best_stream(format_context, AVMEDIA_TYPE_VIDEO, -1,
45-
-1, nullptr, 0);
46-
if (v_stream_no < 0 ||
47-
format_context->streams[v_stream_no]->time_base.den <= 0) {
48-
std::cerr << "FileCapturer::Start av_find_best_stream fail "
49-
<< v_stream_no;//av_err2str(v_stream_no);
50-
av_packet_free(&packet);
51-
avformat_close_input(&format_context);
52-
return -4;
33+
// 获取流信息
34+
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
35+
fprintf(stderr, "无法获取流信息\n");
36+
avformat_close_input(&fmt_ctx);
37+
return ret;
5338
}
54-
AVStream* v_stream = format_context->streams[v_stream_no];
55-
56-
bool first_packet = true;
57-
int64_t last_pts_ms = 0;
58-
int64_t emit_next_packet_ms = 0;
59-
60-
bool need_loop_again = false;
61-
bool running_ = true;
62-
while (running_) {
63-
int ret = av_read_frame(format_context, packet);
64-
if (ret < 0 && ret != AVERROR_EOF) {
65-
std::cerr << "FileCapturer::Start av_read_frame fail "
66-
<< ret;//av_err2str(ret);
67-
running_ = false;
39+
40+
// 查找视频流
41+
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
42+
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
43+
video_stream_index = i;
6844
break;
6945
}
70-
if (ret == AVERROR_EOF) {
71-
if (true) {
72-
std::cerr << "FileCapturer::Start got EOF, loop again";
73-
running_ = false;
74-
need_loop_again = true;
75-
break;
76-
} else {
77-
std::cerr << "FileCapturer::Start got EOF, quit";
78-
running_ = false;
46+
}
47+
if (video_stream_index == -1) {
48+
fprintf(stderr, "未找到视频流\n");
49+
avformat_close_input(&fmt_ctx);
50+
return AVERROR(EINVAL);
51+
}
52+
53+
// 验证是否为H.264编码
54+
AVCodecParameters *codecpar = fmt_ctx->streams[video_stream_index]->codecpar;
55+
if (codecpar->codec_id != AV_CODEC_ID_H264) {
56+
fprintf(stderr, "视频流不是H.264编码\n");
57+
avformat_close_input(&fmt_ctx);
58+
return AVERROR(EINVAL);
59+
}
60+
61+
// 初始化bitstream过滤器(AVCC转Annex B)
62+
const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");
63+
if (!bsf) {
64+
fprintf(stderr, "找不到h264_mp4toannexb过滤器\n");
65+
avformat_close_input(&fmt_ctx);
66+
return AVERROR(EINVAL);
67+
}
68+
if ((ret = av_bsf_alloc(bsf, &bsf_ctx)) < 0) {
69+
avformat_close_input(&fmt_ctx);
70+
return ret;
71+
}
72+
avcodec_parameters_copy(bsf_ctx->par_in, codecpar);
73+
if ((ret = av_bsf_init(bsf_ctx)) < 0) {
74+
av_bsf_free(&bsf_ctx);
75+
avformat_close_input(&fmt_ctx);
76+
return ret;
77+
}
78+
79+
// 打开输出文件
80+
outfile = fopen(output_file, "wb");
81+
if (!outfile) {
82+
fprintf(stderr, "无法打开输出文件\n");
83+
av_bsf_free(&bsf_ctx);
84+
avformat_close_input(&fmt_ctx);
85+
return AVERROR(EIO);
86+
}
87+
88+
AVPacket pkt;
89+
av_init_packet(&pkt);
90+
91+
// 读取并处理数据包
92+
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
93+
if (pkt.stream_index == video_stream_index) {
94+
// 发送原始数据包到过滤器
95+
if ((ret = av_bsf_send_packet(bsf_ctx, &pkt)) < 0) {
96+
av_packet_unref(&pkt);
97+
continue;
98+
}
99+
av_packet_unref(&pkt);
100+
101+
// 接收处理后的数据包
102+
while ((ret = av_bsf_receive_packet(bsf_ctx, &pkt)) == 0) {
103+
fwrite(pkt.data, 1, pkt.size, outfile);
104+
av_packet_unref(&pkt);
105+
}
106+
107+
if (ret == AVERROR(EAGAIN)) {
108+
continue;
109+
} else if (ret < 0 && ret != AVERROR_EOF) {
110+
fprintf(stderr, "过滤器处理错误\n");
79111
break;
80112
}
113+
} else {
114+
av_packet_unref(&pkt);
81115
}
82-
if (packet->stream_index != v_stream->index) {
83-
continue;
84-
}
85-
int64_t now_ms = 0;//rtc::TimeMicros() / 1000;
86-
int64_t this_pts_ms = 1000 * packet->pts * v_stream->time_base.num /
87-
v_stream->time_base.den;
88-
if (first_packet) {
89-
emit_next_packet_ms = now_ms;
90-
last_pts_ms = this_pts_ms;
91-
}
92-
emit_next_packet_ms += this_pts_ms - last_pts_ms;
93-
last_pts_ms = this_pts_ms;
94-
int sleep_ms = (int)(emit_next_packet_ms - now_ms);
95-
96-
// 获取流的时间基
97-
AVRational time_base = v_stream->time_base;
98-
99-
// 将 pts 转换为毫秒
100-
int64_t pts_ms = av_rescale_q(packet->pts, time_base, (AVRational){1, 1000});
101-
first_packet = false;
102-
printf("av_read_frame packet->stream_index %d, v_stream->index %d, v_stream_no %d, packet->pts %d, v_stream->time_base.num %d, v_stream->time_base.den %d, this_pts_ms %d, pts_ms %d\n", packet->stream_index, v_stream->index, v_stream_no, (int) packet->pts, v_stream->time_base.num, v_stream->time_base.den, (int) this_pts_ms, (int) pts_ms);
103-
104-
if (!first_packet && sleep_ms > 5) {
105-
#if defined(WEBRTC_WIN)
106-
Sleep(sleep_ms);
107-
#else
108-
usleep(sleep_ms * 1000);
109-
#endif
110-
}
116+
}
111117

112-
// if (video_callback_ && running_) {
113-
// rtc::scoped_refptr<webrtc::TransitVideoFrameBuffer> frame_buffer =
114-
// rtc::make_ref_counted<webrtc::TransitVideoFrameBuffer>(
115-
// width_, height_, packet->size);
116-
// memcpy(frame_buffer->mutable_data(), packet->data, packet->size);
117-
118-
// video_callback_->OnFrame(
119-
// VideoFrame::Builder()
120-
// .set_video_frame_buffer(frame_buffer)
121-
// .set_rotation(VideoRotation::kVideoRotation_0)
122-
// .set_dummy(false)
123-
// .set_transit(true)
124-
// .set_rtp_timestamp(0)
125-
// .set_timestamp_ms(rtc::TimeMillis())
126-
// .build());
127-
// }
118+
// 冲刷过滤器
119+
av_bsf_send_packet(bsf_ctx, NULL);
120+
while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0) {
121+
fwrite(pkt.data, 1, pkt.size, outfile);
122+
av_packet_unref(&pkt);
128123
}
129124

130-
av_packet_free(&packet);
131-
avformat_close_input(&format_context);
125+
// 清理资源
126+
av_bsf_free(&bsf_ctx);
127+
avformat_close_input(&fmt_ctx);
128+
fclose(outfile);
132129

133130
return 0;
134131
}

0 commit comments

Comments
 (0)