2014-04-01 11:55:18 -07:00
|
|
|
/******************************************************************************
|
|
|
|
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/>.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
#include <obs.h>
|
2014-05-16 00:18:23 -07:00
|
|
|
#include <stdio.h>
|
2014-07-01 13:11:15 -07:00
|
|
|
#include <util/dstr.h>
|
2014-04-01 11:55:18 -07:00
|
|
|
#include <util/array-serializer.h>
|
|
|
|
#include "flv-mux.h"
|
|
|
|
#include "obs-output-ver.h"
|
|
|
|
#include "rtmp-helpers.h"
|
|
|
|
|
2014-04-10 11:59:42 -07:00
|
|
|
/* TODO: FIXME: this is currently hard-coded to h264 and aac! ..not that we'll
|
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
|
|
|
* use anything else for a long time. */
|
|
|
|
|
2014-04-10 11:59:42 -07:00
|
|
|
//#define DEBUG_TIMESTAMPS
|
|
|
|
//#define WRITE_FLV_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
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
#define VIDEO_HEADER_SIZE 5
|
2020-07-09 17:23:41 +08:00
|
|
|
#define VIDEODATA_AVCVIDEOPACKET 7.0
|
|
|
|
#define AUDIODATA_AAC 10.0
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static inline double encoder_bitrate(obs_encoder_t *encoder)
|
2014-04-01 11:55:18 -07:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_data_t *settings = obs_encoder_get_settings(encoder);
|
2014-08-05 11:09:29 -07:00
|
|
|
double bitrate = obs_data_get_double(settings, "bitrate");
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
obs_data_release(settings);
|
|
|
|
return bitrate;
|
|
|
|
}
|
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
#define FLV_INFO_SIZE_OFFSET 42
|
|
|
|
|
|
|
|
void write_file_info(FILE *file, int64_t duration_ms, int64_t size)
|
|
|
|
{
|
|
|
|
char buf[64];
|
|
|
|
char *enc = buf;
|
|
|
|
char *end = enc + sizeof(buf);
|
|
|
|
|
|
|
|
fseek(file, FLV_INFO_SIZE_OFFSET, SEEK_SET);
|
|
|
|
|
|
|
|
enc_num_val(&enc, end, "duration", (double)duration_ms / 1000.0);
|
|
|
|
enc_num_val(&enc, end, "fileSize", (double)size);
|
|
|
|
|
|
|
|
fwrite(buf, 1, enc - buf, file);
|
|
|
|
}
|
|
|
|
|
2020-08-24 13:07:38 -07:00
|
|
|
static void build_flv_meta_data(obs_output_t *context, uint8_t **output,
|
|
|
|
size_t *size)
|
2014-04-01 11:55:18 -07:00
|
|
|
{
|
2014-09-25 17:44:05 -07:00
|
|
|
obs_encoder_t *vencoder = obs_output_get_video_encoder(context);
|
2020-08-24 13:07:38 -07:00
|
|
|
obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, 0);
|
2014-09-25 17:44:05 -07:00
|
|
|
video_t *video = obs_encoder_video(vencoder);
|
|
|
|
audio_t *audio = obs_encoder_audio(aencoder);
|
2014-04-01 11:55:18 -07:00
|
|
|
char buf[4096];
|
|
|
|
char *enc = buf;
|
|
|
|
char *end = enc + sizeof(buf);
|
2014-07-01 13:11:15 -07:00
|
|
|
struct dstr encoder_name = {0};
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2020-08-16 01:46:02 -07:00
|
|
|
enc_str(&enc, end, "@setDataFrame");
|
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
|
|
|
enc_str(&enc, end, "onMetaData");
|
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
*enc++ = AMF_ECMA_ARRAY;
|
2020-08-24 13:07:38 -07:00
|
|
|
enc = AMF_EncodeInt32(enc, end, 20);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
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
|
|
|
enc_num_val(&enc, end, "duration", 0.0);
|
|
|
|
enc_num_val(&enc, end, "fileSize", 0.0);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2020-08-24 13:07:38 -07:00
|
|
|
enc_num_val(&enc, end, "width",
|
|
|
|
(double)obs_encoder_get_width(vencoder));
|
|
|
|
enc_num_val(&enc, end, "height",
|
|
|
|
(double)obs_encoder_get_height(vencoder));
|
|
|
|
|
|
|
|
enc_num_val(&enc, end, "videocodecid", VIDEODATA_AVCVIDEOPACKET);
|
|
|
|
enc_num_val(&enc, end, "videodatarate", encoder_bitrate(vencoder));
|
|
|
|
enc_num_val(&enc, end, "framerate", video_output_get_frame_rate(video));
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2020-07-09 17:23:41 +08:00
|
|
|
enc_num_val(&enc, end, "audiocodecid", AUDIODATA_AAC);
|
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
|
|
|
enc_num_val(&enc, end, "audiodatarate", encoder_bitrate(aencoder));
|
|
|
|
enc_num_val(&enc, end, "audiosamplerate",
|
2015-07-09 10:44:24 -07:00
|
|
|
(double)obs_encoder_get_sample_rate(aencoder));
|
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
|
|
|
enc_num_val(&enc, end, "audiosamplesize", 16.0);
|
|
|
|
enc_num_val(&enc, end, "audiochannels",
|
2014-08-05 15:07:54 -07:00
|
|
|
(double)audio_output_get_channels(audio));
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2014-08-05 15:07:54 -07:00
|
|
|
enc_bool_val(&enc, end, "stereo",
|
|
|
|
audio_output_get_channels(audio) == 2);
|
libobs: Add surround sound audio support
(This commit also modifies the following modules: UI,
deps/media-playback, coreaudio-encoder, decklink, linux-alsa,
linux-pulseaudio, mac-capture, obs-ffmpeg, obs-filters, obs-libfdk,
obs-outputs, win-dshow, and win-wasapi)
Adds surround sound audio support to the core, core plugins, and user
interface.
Compatible streaming services: Twitch, FB 360 live
Compatible protocols: rtmp / mpeg-ts tcp udp
Compatible file formats: mkv mp4 ts (others untested)
Compatible codecs: ffmpeg aac, fdk_aac, CoreAudio aac,
opus, vorbis, pcm (others untested).
Tested streaming servers: wowza, nginx
HLS, mpeg-dash : surround passthrough
Html5 players tested with live surround:
videojs, mediaelement, viblast (hls+dash), hls.js
Decklink: on win32, swap channels order for 5.1 7.1
(due to different channel mapping on wav, mpeg, ffmpeg)
Audio filters: surround working.
Monitoring: surround working (win macOs linux (pulse-audio)).
VST: stereo plugins keep in general only the first two channels.
surround plugins should work (e.g. mcfx does).
OS: win, macOs, linux (alsa, pulse-audio).
Misc: larger audio bitrates unlocked to accommodate more channels
NB: mf-aac only supports mono and stereo + 5.1 on win 10
(not implemented due to lack of usefulness)
Closes jp9000/obs-studio#968
2017-05-27 02:15:54 +02:00
|
|
|
enc_bool_val(&enc, end, "2.1", audio_output_get_channels(audio) == 3);
|
|
|
|
enc_bool_val(&enc, end, "3.1", audio_output_get_channels(audio) == 4);
|
|
|
|
enc_bool_val(&enc, end, "4.0", audio_output_get_channels(audio) == 4);
|
|
|
|
enc_bool_val(&enc, end, "4.1", audio_output_get_channels(audio) == 5);
|
|
|
|
enc_bool_val(&enc, end, "5.1", audio_output_get_channels(audio) == 6);
|
|
|
|
enc_bool_val(&enc, end, "7.1", audio_output_get_channels(audio) == 8);
|
2019-06-22 22:13:45 -07:00
|
|
|
|
2014-07-14 09:52:36 -07:00
|
|
|
dstr_printf(&encoder_name, "%s (libobs version ", MODULE_NAME);
|
|
|
|
|
|
|
|
#ifdef HAVE_OBSCONFIG_H
|
|
|
|
dstr_cat(&encoder_name, OBS_VERSION);
|
|
|
|
#else
|
|
|
|
dstr_catf(&encoder_name, "%d.%d.%d", LIBOBS_API_MAJOR_VER,
|
2014-07-01 13:11:15 -07:00
|
|
|
LIBOBS_API_MINOR_VER, LIBOBS_API_PATCH_VER);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
dstr_cat(&encoder_name, ")");
|
|
|
|
|
|
|
|
enc_str_val(&enc, end, "encoder", encoder_name.array);
|
|
|
|
dstr_free(&encoder_name);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
*enc++ = 0;
|
|
|
|
*enc++ = 0;
|
|
|
|
*enc++ = AMF_OBJECT_END;
|
|
|
|
|
|
|
|
*size = enc - buf;
|
|
|
|
*output = bmemdup(buf, *size);
|
|
|
|
}
|
|
|
|
|
2020-08-24 13:07:38 -07:00
|
|
|
void flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size,
|
|
|
|
bool write_header)
|
2014-04-01 11:55:18 -07:00
|
|
|
{
|
|
|
|
struct array_output_data data;
|
|
|
|
struct serializer s;
|
(API Change) Add support for multiple audio mixers
API changed:
--------------------------
void obs_output_set_audio_encoder(
obs_output_t *output,
obs_encoder_t *encoder);
obs_encoder_t *obs_output_get_audio_encoder(
const obs_output_t *output);
obs_encoder_t *obs_audio_encoder_create(
const char *id,
const char *name,
obs_data_t *settings);
Changed to:
--------------------------
/* 'idx' specifies the track index of the output */
void obs_output_set_audio_encoder(
obs_output_t *output,
obs_encoder_t *encoder,
size_t idx);
/* 'idx' specifies the track index of the output */
obs_encoder_t *obs_output_get_audio_encoder(
const obs_output_t *output,
size_t idx);
/* 'mixer_idx' specifies the mixer index to capture audio from */
obs_encoder_t *obs_audio_encoder_create(
const char *id,
const char *name,
obs_data_t *settings,
size_t mixer_idx);
Overview
--------------------------
This feature allows multiple audio mixers to be used at a time. This
capability was able to be added with surprisingly very little extra
overhead. Audio will not be mixed unless it's assigned to a specific
mixer, and mixers will not mix unless they have an active mix
connection.
Mostly this will be useful for being able to separate out specific audio
for recording versus streaming, but will also be useful for certain
streaming services that support multiple audio streams via RTMP.
I didn't want to use a variable amount of mixers due to the desire to
reduce heap allocations, so currently I set the limit to 4 simultaneous
mixers; this number can be increased later if needed, but honestly I
feel like it's just the right number to use.
Sources:
Sources can now specify which audio mixers their audio is mixed to; this
can be a single mixer or multiple mixers at a time. The
obs_source_set_audio_mixers function sets the audio mixer which an audio
source applies to. For example, 0xF would mean that the source applies
to all four mixers.
Audio Encoders:
Audio encoders now must specify which specific audio mixer they use when
they encode audio data.
Outputs:
Outputs that use encoders can now support multiple audio tracks at once
if they have the OBS_OUTPUT_MULTI_TRACK capability flag set. This is
mostly only useful for certain types of RTMP transmissions, though may
be useful for file formats that support multiple audio tracks as well
later on.
2015-01-14 02:12:08 -08:00
|
|
|
uint8_t *meta_data = NULL;
|
2014-04-01 11:55:18 -07:00
|
|
|
size_t 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
|
|
|
uint32_t start_pos;
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2014-04-02 00:42:12 -07:00
|
|
|
array_output_serializer_init(&s, &data);
|
2020-08-24 13:07:38 -07:00
|
|
|
build_flv_meta_data(context, &meta_data, &meta_data_size);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
2014-05-16 00:18:23 -07:00
|
|
|
if (write_header) {
|
|
|
|
s_write(&s, "FLV", 3);
|
|
|
|
s_w8(&s, 1);
|
|
|
|
s_w8(&s, 5);
|
|
|
|
s_wb32(&s, 9);
|
|
|
|
s_wb32(&s, 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
|
|
|
|
|
|
|
start_pos = serializer_get_pos(&s);
|
|
|
|
|
2014-04-02 00:42:12 -07:00
|
|
|
s_w8(&s, RTMP_PACKET_TYPE_INFO);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
s_wb24(&s, (uint32_t)meta_data_size);
|
|
|
|
s_wb32(&s, 0);
|
|
|
|
s_wb24(&s, 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
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
s_write(&s, meta_data, meta_data_size);
|
|
|
|
|
2017-09-28 06:15:58 -07:00
|
|
|
s_wb32(&s, (uint32_t)serializer_get_pos(&s) - start_pos - 1);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
*output = data.bytes.array;
|
|
|
|
*size = data.bytes.num;
|
|
|
|
|
|
|
|
bfree(meta_data);
|
|
|
|
}
|
|
|
|
|
2014-04-14 02:02:59 -07:00
|
|
|
#ifdef DEBUG_TIMESTAMPS
|
|
|
|
static int32_t last_time = 0;
|
|
|
|
#endif
|
|
|
|
|
2017-09-28 06:04:54 -07:00
|
|
|
static void flv_video(struct serializer *s, int32_t dts_offset,
|
|
|
|
struct encoder_packet *packet, bool is_header)
|
2014-04-01 11:55:18 -07:00
|
|
|
{
|
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
|
|
|
int64_t offset = packet->pts - packet->dts;
|
2017-09-28 06:04:54 -07:00
|
|
|
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
if (!packet->data || !packet->size)
|
|
|
|
return;
|
|
|
|
|
|
|
|
s_w8(s, RTMP_PACKET_TYPE_VIDEO);
|
|
|
|
|
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 DEBUG_TIMESTAMPS
|
|
|
|
blog(LOG_DEBUG, "Video: %lu", time_ms);
|
2014-04-14 02:02:59 -07:00
|
|
|
|
|
|
|
if (last_time > time_ms)
|
|
|
|
blog(LOG_DEBUG, "Non-monotonic");
|
|
|
|
|
|
|
|
last_time = time_ms;
|
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
|
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
s_wb24(s, (uint32_t)packet->size + 5);
|
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
|
|
|
s_wb24(s, time_ms);
|
|
|
|
s_w8(s, (time_ms >> 24) & 0x7F);
|
2014-04-01 11:55:18 -07:00
|
|
|
s_wb24(s, 0);
|
|
|
|
|
|
|
|
/* these are the 5 extra bytes mentioned above */
|
|
|
|
s_w8(s, packet->keyframe ? 0x17 : 0x27);
|
|
|
|
s_w8(s, is_header ? 0 : 1);
|
|
|
|
s_wb24(s, get_ms_time(packet, offset));
|
|
|
|
s_write(s, packet->data, packet->size);
|
|
|
|
|
2017-03-19 07:35:51 -04:00
|
|
|
/* write tag size (starting byte doesn't count) */
|
2017-09-28 06:15:58 -07:00
|
|
|
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
2014-04-01 11:55:18 -07:00
|
|
|
}
|
|
|
|
|
2017-09-28 06:04:54 -07:00
|
|
|
static void flv_audio(struct serializer *s, int32_t dts_offset,
|
|
|
|
struct encoder_packet *packet, bool is_header)
|
2014-04-01 11:55:18 -07:00
|
|
|
{
|
2017-09-28 06:04:54 -07:00
|
|
|
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
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
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
if (!packet->data || !packet->size)
|
|
|
|
return;
|
|
|
|
|
|
|
|
s_w8(s, RTMP_PACKET_TYPE_AUDIO);
|
|
|
|
|
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 DEBUG_TIMESTAMPS
|
|
|
|
blog(LOG_DEBUG, "Audio: %lu", time_ms);
|
2014-04-14 02:02:59 -07:00
|
|
|
|
|
|
|
if (last_time > time_ms)
|
|
|
|
blog(LOG_DEBUG, "Non-monotonic");
|
|
|
|
|
|
|
|
last_time = time_ms;
|
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
|
|
|
|
|
2014-04-01 11:55:18 -07:00
|
|
|
s_wb24(s, (uint32_t)packet->size + 2);
|
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
|
|
|
s_wb24(s, time_ms);
|
|
|
|
s_w8(s, (time_ms >> 24) & 0x7F);
|
2014-04-01 11:55:18 -07:00
|
|
|
s_wb24(s, 0);
|
|
|
|
|
|
|
|
/* these are the two extra bytes mentioned above */
|
|
|
|
s_w8(s, 0xaf);
|
|
|
|
s_w8(s, is_header ? 0 : 1);
|
|
|
|
s_write(s, packet->data, packet->size);
|
|
|
|
|
2017-03-19 07:35:51 -04:00
|
|
|
/* write tag size (starting byte doesn't count) */
|
2017-09-28 06:15:58 -07:00
|
|
|
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
2014-04-01 11:55:18 -07:00
|
|
|
}
|
|
|
|
|
2017-09-28 06:04:54 -07:00
|
|
|
void flv_packet_mux(struct encoder_packet *packet, int32_t dts_offset,
|
2014-04-01 11:55:18 -07:00
|
|
|
uint8_t **output, size_t *size, bool is_header)
|
|
|
|
{
|
|
|
|
struct array_output_data data;
|
|
|
|
struct serializer s;
|
|
|
|
|
|
|
|
array_output_serializer_init(&s, &data);
|
|
|
|
|
|
|
|
if (packet->type == OBS_ENCODER_VIDEO)
|
2017-09-28 06:04:54 -07:00
|
|
|
flv_video(&s, dts_offset, packet, is_header);
|
2014-04-01 11:55:18 -07:00
|
|
|
else
|
2017-09-28 06:04:54 -07:00
|
|
|
flv_audio(&s, dts_offset, packet, is_header);
|
2014-04-01 11:55:18 -07:00
|
|
|
|
|
|
|
*output = data.bytes.array;
|
|
|
|
*size = data.bytes.num;
|
|
|
|
}
|
2020-08-16 02:20:18 -07:00
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* stuff for additional media streams */
|
|
|
|
|
|
|
|
#define s_amf_conststring(s, str) \
|
|
|
|
do { \
|
|
|
|
const size_t len = sizeof(str) - 1; \
|
|
|
|
s_wb16(s, (uint16_t)len); \
|
|
|
|
serialize(s, str, len); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
#define s_amf_double(s, d) \
|
|
|
|
do { \
|
|
|
|
double d_val = d; \
|
|
|
|
uint64_t u_val = *(uint64_t *)&d_val; \
|
|
|
|
s_wb64(s, u_val); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
static void flv_build_additional_meta_data(uint8_t **data, size_t *size)
|
|
|
|
{
|
|
|
|
struct array_output_data out;
|
|
|
|
struct serializer s;
|
|
|
|
|
|
|
|
array_output_serializer_init(&s, &out);
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "@setDataFrame");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "onExpectAdditionalMedia");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "processingIntents");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRICT_ARRAY);
|
|
|
|
s_wb32(&s, 1);
|
|
|
|
{
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "ArchiveProgramNarrationAudio");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ---- */
|
|
|
|
|
|
|
|
s_amf_conststring(&s, "additionalMedia");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "stream0");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "type");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_NUMBER);
|
|
|
|
s_amf_double(&s, RTMP_PACKET_TYPE_AUDIO);
|
|
|
|
|
|
|
|
/* ---- */
|
|
|
|
|
|
|
|
s_amf_conststring(&s, "mediaLabels");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "contentType");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "PNAR");
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
|
|
|
|
/* ---- */
|
|
|
|
|
|
|
|
s_amf_conststring(&s, "defaultMedia");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "audio");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "mediaLabels");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "contentType");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "PRM");
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
|
|
|
|
*data = out.bytes.array;
|
|
|
|
*size = out.bytes.num;
|
|
|
|
}
|
|
|
|
|
2020-08-24 13:07:38 -07:00
|
|
|
void flv_additional_meta_data(obs_output_t *context, uint8_t **data,
|
2020-08-16 02:20:18 -07:00
|
|
|
size_t *size)
|
|
|
|
{
|
2020-08-26 01:34:03 -03:00
|
|
|
UNUSED_PARAMETER(context);
|
2020-08-16 02:20:18 -07:00
|
|
|
struct array_output_data out;
|
|
|
|
struct serializer s;
|
|
|
|
uint8_t *meta_data = NULL;
|
|
|
|
size_t meta_data_size;
|
|
|
|
|
|
|
|
flv_build_additional_meta_data(&meta_data, &meta_data_size);
|
|
|
|
|
|
|
|
array_output_serializer_init(&s, &out);
|
|
|
|
|
|
|
|
s_w8(&s, RTMP_PACKET_TYPE_INFO); //18
|
|
|
|
|
|
|
|
s_wb24(&s, (uint32_t)meta_data_size);
|
|
|
|
s_wb32(&s, 0);
|
|
|
|
s_wb24(&s, 0);
|
|
|
|
|
|
|
|
s_write(&s, meta_data, meta_data_size);
|
|
|
|
bfree(meta_data);
|
|
|
|
|
|
|
|
s_wb32(&s, (uint32_t)serializer_get_pos(&s) - 1);
|
|
|
|
|
|
|
|
*data = out.bytes.array;
|
|
|
|
*size = out.bytes.num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void s_u29(struct serializer *s, uint32_t val)
|
|
|
|
{
|
|
|
|
if (val <= 0x7F) {
|
|
|
|
s_w8(s, val);
|
|
|
|
} else if (val <= 0x3FFF) {
|
|
|
|
s_w8(s, 0x80 | (val >> 7));
|
|
|
|
s_w8(s, val & 0x7F);
|
|
|
|
} else if (val <= 0x1FFFFF) {
|
|
|
|
s_w8(s, 0x80 | (val >> 14));
|
|
|
|
s_w8(s, 0x80 | ((val >> 7) & 0x7F));
|
|
|
|
s_w8(s, val & 0x7F);
|
|
|
|
} else {
|
|
|
|
s_w8(s, 0x80 | (val >> 22));
|
|
|
|
s_w8(s, 0x80 | ((val >> 15) & 0x7F));
|
|
|
|
s_w8(s, 0x80 | ((val >> 8) & 0x7F));
|
|
|
|
s_w8(s, val & 0xFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void s_u29b_value(struct serializer *s, uint32_t val)
|
|
|
|
{
|
|
|
|
s_u29(s, 1 | ((val & 0xFFFFFFF) << 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flv_build_additional_audio(uint8_t **data, size_t *size,
|
|
|
|
struct encoder_packet *packet,
|
|
|
|
bool is_header, size_t index)
|
|
|
|
{
|
2020-08-26 01:34:03 -03:00
|
|
|
UNUSED_PARAMETER(index);
|
2020-08-16 02:20:18 -07:00
|
|
|
struct array_output_data out;
|
|
|
|
struct serializer s;
|
|
|
|
|
|
|
|
array_output_serializer_init(&s, &out);
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "additionalMedia");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_OBJECT);
|
|
|
|
{
|
|
|
|
s_amf_conststring(&s, "id");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_STRING);
|
|
|
|
s_amf_conststring(&s, "stream0");
|
|
|
|
|
|
|
|
/* ----- */
|
|
|
|
|
|
|
|
s_amf_conststring(&s, "media");
|
|
|
|
|
|
|
|
s_w8(&s, AMF_AVMPLUS);
|
|
|
|
s_w8(&s, AMF3_BYTE_ARRAY);
|
|
|
|
s_u29b_value(&s, (uint32_t)packet->size + 2);
|
|
|
|
s_w8(&s, 0xaf);
|
|
|
|
s_w8(&s, is_header ? 0 : 1);
|
|
|
|
s_write(&s, packet->data, packet->size);
|
|
|
|
}
|
|
|
|
s_wb24(&s, AMF_OBJECT_END);
|
|
|
|
|
|
|
|
*data = out.bytes.array;
|
|
|
|
*size = out.bytes.num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flv_additional_audio(struct serializer *s, int32_t dts_offset,
|
|
|
|
struct encoder_packet *packet, bool is_header,
|
|
|
|
size_t index)
|
|
|
|
{
|
|
|
|
int32_t time_ms = get_ms_time(packet, packet->dts) - dts_offset;
|
|
|
|
uint8_t *data;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (!packet->data || !packet->size)
|
|
|
|
return;
|
|
|
|
|
|
|
|
flv_build_additional_audio(&data, &size, packet, is_header, index);
|
|
|
|
|
|
|
|
s_w8(s, RTMP_PACKET_TYPE_INFO); //18
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIMESTAMPS
|
|
|
|
blog(LOG_DEBUG, "Audio2: %lu", time_ms);
|
|
|
|
|
|
|
|
if (last_time > time_ms)
|
|
|
|
blog(LOG_DEBUG, "Non-monotonic");
|
|
|
|
|
|
|
|
last_time = time_ms;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
s_wb24(s, (uint32_t)size);
|
|
|
|
s_wb24(s, time_ms);
|
|
|
|
s_w8(s, (time_ms >> 24) & 0x7F);
|
|
|
|
s_wb24(s, 0);
|
|
|
|
|
|
|
|
serialize(s, data, size);
|
|
|
|
bfree(data);
|
|
|
|
|
|
|
|
s_wb32(s, (uint32_t)serializer_get_pos(s) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void flv_additional_packet_mux(struct encoder_packet *packet,
|
|
|
|
int32_t dts_offset, uint8_t **data, size_t *size,
|
|
|
|
bool is_header, size_t index)
|
|
|
|
{
|
|
|
|
struct array_output_data out;
|
|
|
|
struct serializer s;
|
|
|
|
|
|
|
|
array_output_serializer_init(&s, &out);
|
|
|
|
|
|
|
|
if (packet->type == OBS_ENCODER_VIDEO) {
|
|
|
|
//currently unsupported
|
|
|
|
bcrash("who said you could output an additional video packet?");
|
|
|
|
} else {
|
|
|
|
flv_additional_audio(&s, dts_offset, packet, is_header, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
*data = out.bytes.array;
|
|
|
|
*size = out.bytes.num;
|
|
|
|
}
|