obs-studio/plugins/obs-outputs/rtmp-stream.c

571 lines
14 KiB
C
Raw Normal View History

/******************************************************************************
Copyright (C) 2014 by Hugh Bailey <obs.jim@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
Implement encoder interface (still preliminary) - Implement OBS encoder interface. It was previously incomplete, but now is reaching some level of completion, though probably should still be considered preliminary. I had originally implemented it so that encoders only have a 'reset' function to reset their parameters, but I felt that having both a 'start' and 'stop' function would be useful. Encoders are now assigned to a specific video/audio media output each rather than implicitely assigned to the main obs video/audio contexts. This allows separate encoder contexts that aren't necessarily assigned to the main video/audio context (which is useful for things such as recording specific sources). Will probably have to do this for regular obs outputs as well. When creating an encoder, you must now explicitely state whether that encoder is an audio or video encoder. Audio and video can optionally be automatically converted depending on what the encoder specifies. When something 'attaches' to an encoder, the first attachment starts the encoder, and the encoder automatically attaches to the media output context associated with it. Subsequent attachments won't have the same effect, they will just start receiving the same encoder data when the next keyframe plays (along with SEI if any). When detaching from the encoder, the last detachment will fully stop the encoder and detach the encoder from the media output context associated with the encoder. SEI must actually be exported separately; because new encoder attachments may not always be at the beginning of the stream, the first keyframe they get must have that SEI data in it. If the encoder has SEI data, it needs only add one small function to simply query that SEI data, and then that data will be handled automatically by libobs for all subsequent encoder attachments. - Implement x264 encoder plugin, move x264 files to separate plugin to separate necessary dependencies. - Change video/audio frame output structures to not use const qualifiers to prevent issues with non-const function usage elsewhere. This was an issue when writing the x264 encoder, as the x264 encoder expects non-const frame data. Change stagesurf_map to return a non-const data type to prevent this as well. - Change full range parameter of video scaler to be an enum rather than boolean
2014-03-16 16:21:34 -07:00
#include <obs.h>
#include <obs-avc.h>
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#include <util/platform.h>
#include <util/circlebuf.h>
#include <util/dstr.h>
#include <util/threading.h>
#include "librtmp/rtmp.h"
#include "librtmp/log.h"
#include "flv-mux.h"
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
//#define FILE_TEST
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
//#define TEST_FRAMEDROPS
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
Implement encoder interface (still preliminary) - Implement OBS encoder interface. It was previously incomplete, but now is reaching some level of completion, though probably should still be considered preliminary. I had originally implemented it so that encoders only have a 'reset' function to reset their parameters, but I felt that having both a 'start' and 'stop' function would be useful. Encoders are now assigned to a specific video/audio media output each rather than implicitely assigned to the main obs video/audio contexts. This allows separate encoder contexts that aren't necessarily assigned to the main video/audio context (which is useful for things such as recording specific sources). Will probably have to do this for regular obs outputs as well. When creating an encoder, you must now explicitely state whether that encoder is an audio or video encoder. Audio and video can optionally be automatically converted depending on what the encoder specifies. When something 'attaches' to an encoder, the first attachment starts the encoder, and the encoder automatically attaches to the media output context associated with it. Subsequent attachments won't have the same effect, they will just start receiving the same encoder data when the next keyframe plays (along with SEI if any). When detaching from the encoder, the last detachment will fully stop the encoder and detach the encoder from the media output context associated with the encoder. SEI must actually be exported separately; because new encoder attachments may not always be at the beginning of the stream, the first keyframe they get must have that SEI data in it. If the encoder has SEI data, it needs only add one small function to simply query that SEI data, and then that data will be handled automatically by libobs for all subsequent encoder attachments. - Implement x264 encoder plugin, move x264 files to separate plugin to separate necessary dependencies. - Change video/audio frame output structures to not use const qualifiers to prevent issues with non-const function usage elsewhere. This was an issue when writing the x264 encoder, as the x264 encoder expects non-const frame data. Change stagesurf_map to return a non-const data type to prevent this as well. - Change full range parameter of video scaler to be an enum rather than boolean
2014-03-16 16:21:34 -07:00
struct rtmp_stream {
obs_output_t output;
Implement encoder interface (still preliminary) - Implement OBS encoder interface. It was previously incomplete, but now is reaching some level of completion, though probably should still be considered preliminary. I had originally implemented it so that encoders only have a 'reset' function to reset their parameters, but I felt that having both a 'start' and 'stop' function would be useful. Encoders are now assigned to a specific video/audio media output each rather than implicitely assigned to the main obs video/audio contexts. This allows separate encoder contexts that aren't necessarily assigned to the main video/audio context (which is useful for things such as recording specific sources). Will probably have to do this for regular obs outputs as well. When creating an encoder, you must now explicitely state whether that encoder is an audio or video encoder. Audio and video can optionally be automatically converted depending on what the encoder specifies. When something 'attaches' to an encoder, the first attachment starts the encoder, and the encoder automatically attaches to the media output context associated with it. Subsequent attachments won't have the same effect, they will just start receiving the same encoder data when the next keyframe plays (along with SEI if any). When detaching from the encoder, the last detachment will fully stop the encoder and detach the encoder from the media output context associated with the encoder. SEI must actually be exported separately; because new encoder attachments may not always be at the beginning of the stream, the first keyframe they get must have that SEI data in it. If the encoder has SEI data, it needs only add one small function to simply query that SEI data, and then that data will be handled automatically by libobs for all subsequent encoder attachments. - Implement x264 encoder plugin, move x264 files to separate plugin to separate necessary dependencies. - Change video/audio frame output structures to not use const qualifiers to prevent issues with non-const function usage elsewhere. This was an issue when writing the x264 encoder, as the x264 encoder expects non-const frame data. Change stagesurf_map to return a non-const data type to prevent this as well. - Change full range parameter of video scaler to be an enum rather than boolean
2014-03-16 16:21:34 -07:00
pthread_mutex_t packets_mutex;
struct circlebuf packets;
bool connecting;
pthread_t connect_thread;
bool active;
pthread_t send_thread;
os_sem_t send_sem;
os_event_t stop_event;
struct dstr path, key;
struct dstr username, password;
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
/* frame drop variables */
int64_t drop_threshold_usec;
int64_t min_drop_dts_usec;
int min_priority;
int64_t last_dts_usec;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#ifdef FILE_TEST
FILE *test;
#endif
RTMP rtmp;
Implement encoder interface (still preliminary) - Implement OBS encoder interface. It was previously incomplete, but now is reaching some level of completion, though probably should still be considered preliminary. I had originally implemented it so that encoders only have a 'reset' function to reset their parameters, but I felt that having both a 'start' and 'stop' function would be useful. Encoders are now assigned to a specific video/audio media output each rather than implicitely assigned to the main obs video/audio contexts. This allows separate encoder contexts that aren't necessarily assigned to the main video/audio context (which is useful for things such as recording specific sources). Will probably have to do this for regular obs outputs as well. When creating an encoder, you must now explicitely state whether that encoder is an audio or video encoder. Audio and video can optionally be automatically converted depending on what the encoder specifies. When something 'attaches' to an encoder, the first attachment starts the encoder, and the encoder automatically attaches to the media output context associated with it. Subsequent attachments won't have the same effect, they will just start receiving the same encoder data when the next keyframe plays (along with SEI if any). When detaching from the encoder, the last detachment will fully stop the encoder and detach the encoder from the media output context associated with the encoder. SEI must actually be exported separately; because new encoder attachments may not always be at the beginning of the stream, the first keyframe they get must have that SEI data in it. If the encoder has SEI data, it needs only add one small function to simply query that SEI data, and then that data will be handled automatically by libobs for all subsequent encoder attachments. - Implement x264 encoder plugin, move x264 files to separate plugin to separate necessary dependencies. - Change video/audio frame output structures to not use const qualifiers to prevent issues with non-const function usage elsewhere. This was an issue when writing the x264 encoder, as the x264 encoder expects non-const frame data. Change stagesurf_map to return a non-const data type to prevent this as well. - Change full range parameter of video scaler to be an enum rather than boolean
2014-03-16 16:21:34 -07:00
};
static const char *rtmp_stream_getname(const char *locale)
{
/* TODO: locale stuff */
UNUSED_PARAMETER(locale);
return "RTMP Stream";
}
static void log_rtmp(int level, const char *format, va_list args)
{
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
if (level > RTMP_LOGERROR)
return;
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
blogva(LOG_INFO, format, args);
}
static inline void free_packets(struct rtmp_stream *stream)
{
while (stream->packets.size) {
struct encoder_packet packet;
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
obs_free_encoder_packet(&packet);
}
}
static void rtmp_stream_destroy(void *data)
{
struct rtmp_stream *stream = data;
if (stream) {
free_packets(stream);
dstr_free(&stream->path);
dstr_free(&stream->key);
dstr_free(&stream->username);
dstr_free(&stream->password);
RTMP_Close(&stream->rtmp);
os_event_destroy(stream->stop_event);
os_sem_destroy(stream->send_sem);
pthread_mutex_destroy(&stream->packets_mutex);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
circlebuf_free(&stream->packets);
bfree(stream);
}
}
Implement encoder interface (still preliminary) - Implement OBS encoder interface. It was previously incomplete, but now is reaching some level of completion, though probably should still be considered preliminary. I had originally implemented it so that encoders only have a 'reset' function to reset their parameters, but I felt that having both a 'start' and 'stop' function would be useful. Encoders are now assigned to a specific video/audio media output each rather than implicitely assigned to the main obs video/audio contexts. This allows separate encoder contexts that aren't necessarily assigned to the main video/audio context (which is useful for things such as recording specific sources). Will probably have to do this for regular obs outputs as well. When creating an encoder, you must now explicitely state whether that encoder is an audio or video encoder. Audio and video can optionally be automatically converted depending on what the encoder specifies. When something 'attaches' to an encoder, the first attachment starts the encoder, and the encoder automatically attaches to the media output context associated with it. Subsequent attachments won't have the same effect, they will just start receiving the same encoder data when the next keyframe plays (along with SEI if any). When detaching from the encoder, the last detachment will fully stop the encoder and detach the encoder from the media output context associated with the encoder. SEI must actually be exported separately; because new encoder attachments may not always be at the beginning of the stream, the first keyframe they get must have that SEI data in it. If the encoder has SEI data, it needs only add one small function to simply query that SEI data, and then that data will be handled automatically by libobs for all subsequent encoder attachments. - Implement x264 encoder plugin, move x264 files to separate plugin to separate necessary dependencies. - Change video/audio frame output structures to not use const qualifiers to prevent issues with non-const function usage elsewhere. This was an issue when writing the x264 encoder, as the x264 encoder expects non-const frame data. Change stagesurf_map to return a non-const data type to prevent this as well. - Change full range parameter of video scaler to be an enum rather than boolean
2014-03-16 16:21:34 -07:00
static void *rtmp_stream_create(obs_data_t settings, obs_output_t output)
{
struct rtmp_stream *stream = bzalloc(sizeof(struct rtmp_stream));
stream->output = output;
pthread_mutex_init_value(&stream->packets_mutex);
RTMP_Init(&stream->rtmp);
RTMP_LogSetCallback(log_rtmp);
if (pthread_mutex_init(&stream->packets_mutex, NULL) != 0)
goto fail;
if (os_event_init(&stream->stop_event, OS_EVENT_TYPE_MANUAL) != 0)
goto fail;
UNUSED_PARAMETER(settings);
return stream;
fail:
rtmp_stream_destroy(stream);
return NULL;
}
static void rtmp_stream_stop(void *data)
{
struct rtmp_stream *stream = data;
void *ret;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#ifdef FILE_TEST
fclose(stream->test);
#endif
os_event_signal(stream->stop_event);
if (stream->connecting)
pthread_join(stream->connect_thread, &ret);
if (stream->active) {
obs_output_end_data_capture(stream->output);
os_sem_post(stream->send_sem);
pthread_join(stream->send_thread, &ret);
}
os_event_reset(stream->stop_event);
}
static inline void set_rtmp_str(AVal *val, const char *str)
{
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
bool valid = (str && *str);
val->av_val = valid ? (char*)str : NULL;
val->av_len = valid ? (int)strlen(str) : 0;
}
static inline void set_rtmp_dstr(AVal *val, struct dstr *str)
{
bool valid = !dstr_isempty(str);
val->av_val = valid ? str->array : NULL;
val->av_len = valid ? (int)str->len : 0;
}
static inline bool get_next_packet(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
bool new_packet = false;
pthread_mutex_lock(&stream->packets_mutex);
if (stream->packets.size) {
circlebuf_pop_front(&stream->packets, packet,
sizeof(struct encoder_packet));
new_packet = true;
}
pthread_mutex_unlock(&stream->packets_mutex);
return new_packet;
}
static int send_packet(struct rtmp_stream *stream,
struct encoder_packet *packet, bool is_header)
{
uint8_t *data;
size_t size;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
int ret = 0;
flv_packet_mux(packet, &data, &size, is_header);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#ifdef FILE_TEST
fwrite(data, 1, size, stream->test);
#else
ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#endif
bfree(data);
obs_free_encoder_packet(packet);
return ret;
}
static bool send_remaining_packets(struct rtmp_stream *stream)
{
struct encoder_packet packet;
while (get_next_packet(stream, &packet))
if (send_packet(stream, &packet, false) < 0)
return false;
return true;
}
static void *send_thread(void *data)
{
struct rtmp_stream *stream = data;
bool disconnected = false;
while (os_sem_wait(stream->send_sem) == 0) {
struct encoder_packet packet;
if (os_event_try(stream->stop_event) != EAGAIN)
break;
if (!get_next_packet(stream, &packet))
continue;
if (send_packet(stream, &packet, false) < 0) {
disconnected = true;
break;
}
}
if (!disconnected && !send_remaining_packets(stream))
disconnected = true;
if (disconnected)
free_packets(stream);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
if (os_event_try(stream->stop_event) == EAGAIN) {
pthread_detach(stream->send_thread);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
obs_output_signal_stop(stream->output, OBS_OUTPUT_DISCONNECTED);
}
stream->active = false;
return NULL;
}
static void send_meta_data(struct rtmp_stream *stream)
{
uint8_t *meta_data;
size_t meta_data_size;
flv_meta_data(stream->output, &meta_data, &meta_data_size);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#ifdef FILE_TEST
fwrite(meta_data, 1, meta_data_size, stream->test);
#else
RTMP_Write(&stream->rtmp, (char*)meta_data, (int)meta_data_size);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#endif
bfree(meta_data);
}
static void send_audio_header(struct rtmp_stream *stream)
{
obs_output_t context = stream->output;
obs_encoder_t aencoder = obs_output_get_audio_encoder(context);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
uint8_t *header;
struct encoder_packet packet = {
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
.type = OBS_ENCODER_AUDIO,
.timebase_den = 1
};
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
obs_encoder_get_extra_data(aencoder, &header, &packet.size);
packet.data = bmemdup(header, packet.size);
send_packet(stream, &packet, true);
}
static void send_video_header(struct rtmp_stream *stream)
{
obs_output_t context = stream->output;
obs_encoder_t vencoder = obs_output_get_video_encoder(context);
uint8_t *header;
size_t size;
struct encoder_packet packet = {
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
.type = OBS_ENCODER_VIDEO,
.timebase_den = 1,
.keyframe = true
};
obs_encoder_get_extra_data(vencoder, &header, &size);
packet.size = obs_parse_avc_header(&packet.data, header, size);
send_packet(stream, &packet, true);
}
static void send_headers(struct rtmp_stream *stream)
{
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#ifdef FILE_TEST
stream->test = os_fopen("D:\\bla.flv", "wb");
#endif
send_meta_data(stream);
send_audio_header(stream);
send_video_header(stream);
}
static inline bool reset_semaphore(struct rtmp_stream *stream)
{
os_sem_destroy(stream->send_sem);
return os_sem_init(&stream->send_sem, 0) == 0;
}
#ifdef _WIN32
#define socklen_t int
#endif
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
#define MIN_SENDBUF_SIZE 65535
static void adjust_sndbuf_size(struct rtmp_stream *stream, int new_size)
{
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
int cur_sendbuf_size = new_size;
socklen_t int_size = sizeof(int);
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
#ifndef TEST_FRAMEDROPS
getsockopt(stream->rtmp.m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF,
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
(char*)&cur_sendbuf_size, &int_size);
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
if (cur_sendbuf_size < new_size) {
cur_sendbuf_size = new_size;
#else
{cur_sendbuf_size = 1024*8;
#endif
setsockopt(stream->rtmp.m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF,
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
(const char*)&cur_sendbuf_size, int_size);
}
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
}
static int init_send(struct rtmp_stream *stream)
{
int ret;
#if defined(_WIN32) && !defined(FILE_TEST)
adjust_sndbuf_size(stream, MIN_SENDBUF_SIZE);
#endif
reset_semaphore(stream);
ret = pthread_create(&stream->send_thread, NULL, send_thread, stream);
if (ret != 0) {
RTMP_Close(&stream->rtmp);
return OBS_OUTPUT_FAIL;
}
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
stream->active = true;
send_headers(stream);
obs_output_begin_data_capture(stream->output, 0);
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
return OBS_OUTPUT_SUCCESS;
}
static int try_connect(struct rtmp_stream *stream)
{
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
#ifndef FILE_TEST
if (!RTMP_SetupURL2(&stream->rtmp, stream->path.array,
stream->key.array))
return OBS_OUTPUT_BAD_PATH;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
RTMP_EnableWrite(&stream->rtmp);
set_rtmp_dstr(&stream->rtmp.Link.pubUser, &stream->username);
set_rtmp_dstr(&stream->rtmp.Link.pubPasswd, &stream->password);
stream->rtmp.Link.swfUrl = stream->rtmp.Link.tcUrl;
set_rtmp_str(&stream->rtmp.Link.flashVer,
"FMLE/3.0 (compatible; FMSc/1.0)");
stream->rtmp.m_outChunkSize = 4096;
stream->rtmp.m_bSendChunkSizeInfo = true;
stream->rtmp.m_bUseNagle = true;
if (!RTMP_Connect(&stream->rtmp, NULL))
return OBS_OUTPUT_CONNECT_FAILED;
if (!RTMP_ConnectStream(&stream->rtmp, 0))
return OBS_OUTPUT_INVALID_STREAM;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
#endif
return init_send(stream);
}
static void *connect_thread(void *data)
{
struct rtmp_stream *stream = data;
int ret = try_connect(stream);
if (ret != OBS_OUTPUT_SUCCESS)
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
obs_output_signal_stop(stream->output, ret);
if (os_event_try(stream->stop_event) == EAGAIN)
pthread_detach(stream->connect_thread);
stream->connecting = false;
return NULL;
}
static bool rtmp_stream_start(void *data)
{
struct rtmp_stream *stream = data;
obs-studio UI: Implement stream settings UI - Updated the services API so that it links up with an output and the output gets data from that service rather than via settings. This allows the service context to have control over how an output is used, and makes it so that the URL/key/etc isn't necessarily some static setting. Also, if the service is attached to an output, it will stick around until the output is destroyed. - The settings interface has been updated so that it can allow the usage of service plugins. What this means is that now you can create a service plugin that can control aspects of the stream, and it allows each service to create their own user interface if they create a service plugin module. - Testing out saving of current service information. Saves/loads from JSON in to obs_data_t, seems to be working quite nicely, and the service object information is saved/preserved on exit, and loaded again on startup. - I agonized over the settings user interface for days, and eventually I just decided that the only way that users weren't going to be fumbling over options was to split up the settings in to simple/basic output, pre-configured, and then advanced for advanced use (such as multiple outputs or services, which I'll implement later). This was particularly painful to really design right, I wanted more features and wanted to include everything in one interface but ultimately just realized from experience that users are just not technically knowledgable about it and will end up fumbling with the settings rather than getting things done. Basically, what this means is that casual users only have to enter in about 3 things to configure their stream: Stream key, audio bitrate, and video bitrate. I am really happy with this interface for those types of users, but it definitely won't be sufficient for advanced usage or for custom outputs, so that stuff will have to be separated. - Improved the JSON usage for the 'common streaming services' context, I realized that JSON arrays are there to ensure sorting, while forgetting that general items are optimized for hashing. So basically I'm just using arrays now to sort items in it.
2014-04-24 01:49:07 -07:00
obs_service_t service = obs_output_get_service(stream->output);
obs_data_t settings;
if (!obs_output_can_begin_data_capture(stream->output, 0))
return false;
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
if (!obs_output_initialize_encoders(stream->output, 0))
return false;
settings = obs_output_get_settings(stream->output);
obs-studio UI: Implement stream settings UI - Updated the services API so that it links up with an output and the output gets data from that service rather than via settings. This allows the service context to have control over how an output is used, and makes it so that the URL/key/etc isn't necessarily some static setting. Also, if the service is attached to an output, it will stick around until the output is destroyed. - The settings interface has been updated so that it can allow the usage of service plugins. What this means is that now you can create a service plugin that can control aspects of the stream, and it allows each service to create their own user interface if they create a service plugin module. - Testing out saving of current service information. Saves/loads from JSON in to obs_data_t, seems to be working quite nicely, and the service object information is saved/preserved on exit, and loaded again on startup. - I agonized over the settings user interface for days, and eventually I just decided that the only way that users weren't going to be fumbling over options was to split up the settings in to simple/basic output, pre-configured, and then advanced for advanced use (such as multiple outputs or services, which I'll implement later). This was particularly painful to really design right, I wanted more features and wanted to include everything in one interface but ultimately just realized from experience that users are just not technically knowledgable about it and will end up fumbling with the settings rather than getting things done. Basically, what this means is that casual users only have to enter in about 3 things to configure their stream: Stream key, audio bitrate, and video bitrate. I am really happy with this interface for those types of users, but it definitely won't be sufficient for advanced usage or for custom outputs, so that stuff will have to be separated. - Improved the JSON usage for the 'common streaming services' context, I realized that JSON arrays are there to ensure sorting, while forgetting that general items are optimized for hashing. So basically I'm just using arrays now to sort items in it.
2014-04-24 01:49:07 -07:00
dstr_copy(&stream->path, obs_service_get_url(service));
dstr_copy(&stream->key, obs_service_get_key(service));
dstr_copy(&stream->username, obs_service_get_username(service));
dstr_copy(&stream->password, obs_service_get_password(service));
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
stream->drop_threshold_usec =
(int64_t)obs_data_getint(settings, "drop_threshold");
obs_data_release(settings);
return pthread_create(&stream->connect_thread, NULL, connect_thread,
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
stream) == 0;
}
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
static inline bool add_packet(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
circlebuf_push_back(&stream->packets, packet,
sizeof(struct encoder_packet));
stream->last_dts_usec = packet->dts_usec;
return true;
}
static inline size_t num_buffered_packets(struct rtmp_stream *stream)
{
return stream->packets.size / sizeof(struct encoder_packet);
}
static void drop_frames(struct rtmp_stream *stream)
{
struct circlebuf new_buf = {0};
int drop_priority = 0;
uint64_t last_drop_dts_usec = 0;
blog(LOG_DEBUG, "Previous packet count: %d",
(int)num_buffered_packets(stream));
circlebuf_reserve(&new_buf, sizeof(struct encoder_packet) * 8);
while (stream->packets.size) {
struct encoder_packet packet;
circlebuf_pop_front(&stream->packets, &packet, sizeof(packet));
last_drop_dts_usec = packet.dts_usec;
if (packet.type == OBS_ENCODER_AUDIO) {
circlebuf_push_back(&new_buf, &packet, sizeof(packet));
} else {
if (drop_priority < packet.drop_priority)
drop_priority = packet.drop_priority;
obs_free_encoder_packet(&packet);
}
}
circlebuf_free(&stream->packets);
stream->packets = new_buf;
stream->min_priority = drop_priority;
stream->min_drop_dts_usec = last_drop_dts_usec;
blog(LOG_DEBUG, "New packet count: %d",
(int)num_buffered_packets(stream));
}
static void check_to_drop_frames(struct rtmp_stream *stream)
{
struct encoder_packet first;
int64_t buffer_duration_usec;
if (num_buffered_packets(stream) < 5)
return;
circlebuf_peek_front(&stream->packets, &first, sizeof(first));
/* do not drop frames if frames were just dropped within this time */
if (first.dts_usec < stream->min_drop_dts_usec)
return;
/* if the amount of time stored in the buffered packets waiting to be
* sent is higher than threshold, drop frames */
buffer_duration_usec = stream->last_dts_usec - first.dts_usec;
if (buffer_duration_usec > stream->drop_threshold_usec) {
drop_frames(stream);
blog(LOG_INFO, "dropping %lld worth of frames",
buffer_duration_usec);
}
}
static bool add_video_packet(struct rtmp_stream *stream,
struct encoder_packet *packet)
{
check_to_drop_frames(stream);
/* if currently dropping frames, drop packets until it reaches the
* desired priority */
if (packet->priority < stream->min_priority)
return false;
else
stream->min_priority = 0;
return add_packet(stream, packet);
}
static void rtmp_stream_data(void *data, struct encoder_packet *packet)
{
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
struct rtmp_stream *stream = data;
struct encoder_packet new_packet;
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
bool added_packet;
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
if (packet->type == OBS_ENCODER_VIDEO)
obs_parse_avc_packet(&new_packet, packet);
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
else
obs_duplicate_encoder_packet(&new_packet, packet);
pthread_mutex_lock(&stream->packets_mutex);
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
added_packet = (packet->type == OBS_ENCODER_VIDEO) ?
add_video_packet(stream, &new_packet) :
add_packet(stream, &new_packet);
pthread_mutex_unlock(&stream->packets_mutex);
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
if (added_packet)
os_sem_post(stream->send_sem);
else
obs_free_encoder_packet(&new_packet);
}
static void rtmp_stream_defaults(obs_data_t defaults)
{
obs_data_set_default_int(defaults, "drop_threshold", 600000);
}
static obs_properties_t rtmp_stream_properties(const char *locale)
{
obs_properties_t props = obs_properties_create(locale);
/* TODO: locale */
obs_properties_add_text(props, "path", "Stream URL", OBS_TEXT_DEFAULT);
obs_properties_add_text(props, "key", "Stream Key", OBS_TEXT_PASSWORD);
obs_properties_add_text(props, "username", "User Name",
OBS_TEXT_DEFAULT);
obs_properties_add_text(props, "password", "Password",
OBS_TEXT_PASSWORD);
return props;
}
struct obs_output_info rtmp_output_info = {
.id = "rtmp_output",
obs-studio UI: Implement stream settings UI - Updated the services API so that it links up with an output and the output gets data from that service rather than via settings. This allows the service context to have control over how an output is used, and makes it so that the URL/key/etc isn't necessarily some static setting. Also, if the service is attached to an output, it will stick around until the output is destroyed. - The settings interface has been updated so that it can allow the usage of service plugins. What this means is that now you can create a service plugin that can control aspects of the stream, and it allows each service to create their own user interface if they create a service plugin module. - Testing out saving of current service information. Saves/loads from JSON in to obs_data_t, seems to be working quite nicely, and the service object information is saved/preserved on exit, and loaded again on startup. - I agonized over the settings user interface for days, and eventually I just decided that the only way that users weren't going to be fumbling over options was to split up the settings in to simple/basic output, pre-configured, and then advanced for advanced use (such as multiple outputs or services, which I'll implement later). This was particularly painful to really design right, I wanted more features and wanted to include everything in one interface but ultimately just realized from experience that users are just not technically knowledgable about it and will end up fumbling with the settings rather than getting things done. Basically, what this means is that casual users only have to enter in about 3 things to configure their stream: Stream key, audio bitrate, and video bitrate. I am really happy with this interface for those types of users, but it definitely won't be sufficient for advanced usage or for custom outputs, so that stuff will have to be separated. - Improved the JSON usage for the 'common streaming services' context, I realized that JSON arrays are there to ensure sorting, while forgetting that general items are optimized for hashing. So basically I'm just using arrays now to sort items in it.
2014-04-24 01:49:07 -07:00
.flags = OBS_OUTPUT_AV |
OBS_OUTPUT_ENCODED |
OBS_OUTPUT_SERVICE,
.getname = rtmp_stream_getname,
.create = rtmp_stream_create,
.destroy = rtmp_stream_destroy,
.start = rtmp_stream_start,
.stop = rtmp_stream_stop,
.encoded_packet = rtmp_stream_data,
RTMP output: Implement frame drop code A little bit of history about frame dropping: I did a large number of experiments with frame dropping in old versions of OBS1, and it's not an easy thing to deal with. I tried just about everything from standard i-frame delay, to large buffers, to dumping packets, to super-unnecessarily-complex things that just ended up causing more problems than they was worth. When I did my experiments, I found that the most ideal frame drop system (in terms of reducing the amount of total data that needed to be dropped) was in the 0.4xx days where I had a 3 second frame-drop buffer where I could calculate the actual buffer size in bytes, and then intellgently choose packets in that buffer to trim it down to a specific size while minimizing the number of p-frames and i-frames dropped, and preventing the actual impact of dropped frames on the stream. The downside of it was that it required too much extra latency, and far too many people complained about it, so it was removed in favor of the current system. The current system I just refer to just as 'packet dumping', which when combined with low keyframe intervals (like most services use these days), is the next-best method from my experience. Just dump the buffer when you reach a threshold of buffering (which I prefer to measure with time rather than in size), then wait for a new i-frame. Simple, effective, and reduces the risk of consecutive buffering, while still having fairly low impact on the stream output due to the low keyframe interval of services. By the way, audio will not (and should not ever) be dropped, lest you end up with syncing issues (among other nasty things) specific to server implementation.
2014-04-12 04:34:15 -07:00
.defaults = rtmp_stream_defaults,
Implement RTMP module (still needs drop code) - Implement the RTMP output module. This time around, we just use a simple FLV muxer, then just write to the stream with RTMP_Write. Easy and effective. - Fix the FLV muxer, the muxer now outputs proper FLV packets. - Output API: * When using encoders, automatically interleave encoded packets before sending it to the output. * Pair encoders and have them automatically wait for the other to start to ensure sync. * Change 'obs_output_signal_start_fail' to 'obs_output_signal_stop' because it was a bit confusing, and doing this makes a lot more sense for outputs that need to stop suddenly (disconnections/etc). - Encoder API: * Remove some unnecessary encoder functions from the actual API and make them internal. Most of the encoder functions are handled automatically by outputs anyway, so there's no real need to expose them and end up inadvertently confusing plugin writers. * Have audio encoders wait for the video encoder to get a frame, then start at the exact data point that the first video frame starts to ensure the most accrate sync of video/audio possible. * Add a required 'frame_size' callback for audio encoders that returns the expected number of frames desired to encode with. This way, the libobs encoder API can handle the circular buffering internally automatically for the encoder modules, so encoder writers don't have to do it themselves. - Fix a few bugs in the serializer interface. It was passing the wrong variable for the data in a few cases. - If a source has video, make obs_source_update defer the actual update callback until the tick function is called to prevent threading issues.
2014-04-07 22:00:10 -07:00
.properties = rtmp_stream_properties
};