当前位置:   article > 正文

OBS源码分析三RTMP推流输出_obs源代码

obs源代码

1.第一步先看RTMP推流输出流程图

 

2.第二步RTMP输出代码详细步骤说明 

首先是RtmpOutput输出对象的创建和编码器绑定

  1. RtmpOutput::RtmpOutput() {
  2. CreateOutputWithUniqueName();
  3. }
  4. RtmpOutput::~RtmpOutput()
  5. {
  6. obs_encoder_release(videoEncoder_);
  7. obs_encoder_release(delayVideoEncoder_);
  8. }
  9. void RtmpOutput::CreateOutputWithUniqueName() {
  10. uid_++;
  11. auto uid = uid_.load();
  12. std::string rtmpNameFormat = "rtmp_stream_%d";
  13. std::string rtmpOutputName = string_format(rtmpNameFormat, uid);
  14. obs_data_t* rtmpSettings = obs_data_create();
  15. SetDefaultRtmpSettings(rtmpSettings);
  16. auto rtmpSettingsGuard = gsl::finally([&]() { obs_data_release(rtmpSettings); });
  17. output_ = obs_output_create("rtmp_output", rtmpOutputName.c_str(),
  18. nullptr, nullptr);
  19. UpdateOutputSettings(rtmpSettings);
  20. auto rtmpOutputGuard = gsl::finally([&]() { obs_output_release(output_); });
  21. std::string rtmpServiceNameFormat = "rtmp_service_%d";
  22. std::string rtmpServiceName = string_format(rtmpServiceNameFormat, uid);
  23. service_ = obs_service_create("rtmp_custom", rtmpServiceName.c_str(), nullptr,
  24. nullptr);
  25. auto serviceGuard = gsl::finally([&]() { obs_service_release(service_); });
  26. obs_output_set_service(output_, service_);
  27. }

调用obs_output_create()函数,根据输出id创建推流对象,与创建编码对象类似,推流对象在加载模块时已添加到obs->output_types中,获取到的推流输出对象赋值给streamOutput指针调用obs_output_set_video_encoder()函数,将推流输出video_encoder设置为编码器;

  1. bool obs_output_start(obs_output_t *output)
  2. {
  3. bool encoded;
  4. if (!obs_output_valid(output, "obs_output_start"))
  5. return false;
  6. if (!output->context.data)
  7. return false;
  8. output->reconnect_total_retries = 0;
  9. encoded = (output->info.flags & OBS_OUTPUT_ENCODED) != 0;
  10. if (encoded && output->delay_sec) {
  11. return obs_output_delay_start(output);
  12. } else {
  13. if (obs_output_actual_start(output)) {
  14. do_output_signal(output, "starting");
  15. return true;
  16. }
  17. return false;
  18. }
  19. }
  1. 调用obs_output_start() -> obs_output_actual_start() 回调推流对象output->info.start()回调函数开启推流,其中start绑定至rtmp_stream_start()

  1. bool obs_output_actual_start(obs_output_t *output)
  2. {
  3. bool success = false;
  4. os_event_wait(output->connecting_event);
  5. if (delay_active(output) && delay_capturing(output)) {
  6. os_event_signal(output->connecting_event);
  7. return true;
  8. }
  9. os_event_wait(output->stopping_event);
  10. output->stop_code = 0;
  11. if (output->last_error_message) {
  12. bfree(output->last_error_message);
  13. output->last_error_message = NULL;
  14. }
  15. blog(LOG_INFO, "output %s actual start", obs_output_get_name(output));
  16. if (output->context.data) {
  17. success = output->info.start(output->context.data);
  18. if (!success) {
  19. if (output->mixer) {
  20. obs_stop_core_audio_mix(output->mixer);
  21. output->mixer = NULL;
  22. }
  23. if (output->video_output) {
  24. obs_stop_video_output(output->video_output);
  25. output->video_output = NULL;
  26. }
  27. os_event_signal(output->connecting_event);
  28. blog(LOG_INFO, "output %s actual start return false", obs_output_get_name(output));
  29. }
  30. }
  31. if (success && output->video) {
  32. output->starting_frame_count =
  33. video_output_get_total_frames(output->video);
  34. output->starting_drawn_count = obs->video.total_frames;
  35. output->starting_lagged_count = obs->video.lagged_frames;
  36. }
  37. if (os_atomic_load_long(&output->delay_restart_refs))
  38. os_atomic_dec_long(&output->delay_restart_refs);
  39. output->caption_timestamp = 0;
  40. return success;
  41. }

 static bool rtmp_stream_start(void *data),创建线程,执行connect_thread()函数,static void *connect_thread(void *data)

init_connect()初始化推流,调用free_packets清空stream->packets,获取推流设置,赋值到stream,try_connect()连接rtmp服务器​​​​​​​;

  1. static void *connect_thread(void *data)
  2. {
  3. struct rtmp_stream *stream = data;
  4. int ret;
  5. os_set_thread_name("rtmp-stream: connect_thread");
  6. if (!init_connect(stream)) {
  7. obs_output_signal_stop(stream->output, OBS_OUTPUT_BAD_PATH);
  8. return NULL;
  9. }
  10. ret = try_connect(stream);
  11. if (ret != OBS_OUTPUT_SUCCESS) {
  12. obs_output_signal_stop(stream->output, ret);
  13. info("Connection to %s failed: %d", stream->path.array, ret);
  14. }
  15. if (!stopping(stream))
  16. pthread_detach(stream->connect_thread);
  17. os_atomic_set_bool(&stream->connecting, false);
  18. return NULL;
  19. }

 RTMP_Init(&stream->rtmp)初始化rtmp客户端,设置推流服务器地址、用户名、密码、流地址、音频编码名称(为何没有添加视频编码名称);

RTMP_Connect()连接rtmp服务器;

RTMP_ConnectStream()连接rtmp流地址;
init_send()启动发送函数,reset_semaphore()重置发送信号量,创建推流执行线程send_thread,发送视频关键数send_meta_data();

然后开启推流数据捕获obs_output_begin_data_capture();

send_thread()线程函数:循环等待信号量stream->send_sem 被唤醒,唤醒后 get_next_packet()取出队列中的第一个已编码数据包,执行 send_packet 函数,调用flv_packet_mux进行flv数据封包,再调用RTMP_Write()发送数据包,完成视频数据推流.

  1. static void *send_thread(void *data)
  2. {
  3. struct rtmp_stream *stream = data;
  4. os_set_thread_name("rtmp-stream: send_thread");
  5. while (os_sem_wait(stream->send_sem) == 0) {
  6. struct encoder_packet packet;
  7. if (stopping(stream) && stream->stop_ts == 0) {
  8. break;
  9. }
  10. if (!get_next_packet(stream, &packet))
  11. continue;
  12. if (stopping(stream)) {
  13. if (can_shutdown_stream(stream, &packet)) {
  14. obs_encoder_packet_release(&packet);
  15. break;
  16. }
  17. }
  18. if (!stream->sent_headers) {
  19. if (!send_headers(stream)) {
  20. os_atomic_set_bool(&stream->disconnected, true);
  21. break;
  22. }
  23. }
  24. if (send_packet(stream, &packet, false, packet.track_idx) < 0) {
  25. os_atomic_set_bool(&stream->disconnected, true);
  26. break;
  27. }
  28. }
  29. if (disconnected(stream)) {
  30. info("Disconnected from %s", stream->path.array);
  31. } else {
  32. info("User stopped the stream");
  33. }
  34. if (stream->new_socket_loop) {
  35. os_event_signal(stream->send_thread_signaled_exit);
  36. os_event_signal(stream->buffer_has_data_event);
  37. pthread_join(stream->socket_thread, NULL);
  38. stream->socket_thread_active = false;
  39. stream->rtmp.m_bCustomSend = false;
  40. }
  41. set_output_error(stream);
  42. RTMP_Close(&stream->rtmp);
  43. if (!stopping(stream)) {
  44. pthread_detach(stream->send_thread);
  45. obs_output_signal_stop(stream->output, stream->sent_headers? OBS_OUTPUT_DISCONNECTED: OBS_OUTPUT_CONNECT_FAILED);
  46. } else {
  47. obs_output_end_data_capture(stream->output);
  48. }
  49. free_packets(stream);
  50. os_event_reset(stream->stop_event);
  51. os_atomic_set_bool(&stream->active, false);
  52. stream->sent_headers = false;
  53. return NULL;
  54. }

 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/194931
推荐阅读
相关标签
  

闽ICP备14008679号