Skip to content

Commit

Permalink
feat: generate media codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
ireader committed Dec 23, 2023
1 parent 0ae77c1 commit b1e08e7
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 41 deletions.
3 changes: 2 additions & 1 deletion libdash/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ OUTFILE = libdash.a
INCLUDES = . \
./include \
../libmov/include \
../libhls/include
../libhls/include \
../libflv/include

#-------------------------------Source-------------------------------
#
Expand Down
8 changes: 4 additions & 4 deletions libdash/libdash.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;../libflv/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -105,7 +105,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;../libflv/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -120,7 +120,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;../libflv/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -137,7 +137,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;OS_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.;include;../libmov/include;../libhls/include;../libflv/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand Down
104 changes: 68 additions & 36 deletions libdash/src/dash-mpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#include "dash-proto.h"
#include "mov-format.h"
#include "fmp4-writer.h"
#include "mpeg4-hevc.h"
#include "mpeg4-vvc.h"
#include "mpeg4-avc.h"
#include "mpeg4-aac.h"
#include "list.h"
#include <time.h>
#include <errno.h>
Expand Down Expand Up @@ -48,6 +52,8 @@ struct dash_adaptation_set_t

int seq;
uint8_t object;
char name[8]; // H264/H265/H266/AAC
char codecs[64]; // avc1.x.x.x

union
{
Expand All @@ -56,12 +62,6 @@ struct dash_adaptation_set_t
int width;
int height;
int frame_rate;
struct
{
uint8_t profile;
uint8_t compatibility;
uint8_t level;
} avc;
} video;

struct
Expand All @@ -87,6 +87,15 @@ struct dash_mpd_t
dash_mpd_segment handler;
void* param;

union
{
struct mpeg4_avc_t avc;
struct mpeg4_hevc_t hevc;
struct mpeg4_vvc_t vvc;

struct mpeg4_aac_t aac;
} v;

int count; // adaptation set count
struct dash_adaptation_set_t tracks[N_TRACK];
};
Expand Down Expand Up @@ -276,23 +285,53 @@ int dash_mpd_add_video_adaptation_set(struct dash_mpd_t* mpd, const char* prefix
if (mpd->count + 1 >= N_TRACK || extra_data_size < 4 || r >= N_NAME)
return -1;

assert(MOV_OBJECT_H264 == object);
assert(((const uint8_t*)extra_data)[0] == 1); // configurationVersion
assert(MOV_OBJECT_H264 == object || MOV_OBJECT_H265 == object || MOV_OBJECT_H266 == object || MOV_OBJECT_AV1 == object);
track = &mpd->tracks[mpd->count];
memcpy(track->prefix, prefix, r);
switch (object)
{
case MOV_OBJECT_H264:
r = mpeg4_avc_decoder_configuration_record_load(extra_data, extra_data_size, &mpd->v.avc);
if (r <= 0)
return -EINVAL; // invalid extra_data
snprintf(track->name, sizeof(track->name), "%s", "H264");
mpeg4_avc_codecs(&mpd->v.avc, track->codecs, sizeof(track->codecs));
break;

case MOV_OBJECT_H265:
r = mpeg4_hevc_decoder_configuration_record_load(extra_data, extra_data_size, &mpd->v.hevc);
if (r <= 0)
return -EINVAL; // invalid extra_data
snprintf(track->name, sizeof(track->name), "%s", "H265");
mpeg4_hevc_codecs(&mpd->v.hevc, track->codecs, sizeof(track->codecs));
break;

case MOV_OBJECT_H266:
r = mpeg4_vvc_decoder_configuration_record_load(extra_data, extra_data_size, &mpd->v.vvc);
if (r <= 0)
return -EINVAL; // invalid extra_data
snprintf(track->name, sizeof(track->name), "%s", "H266");
mpeg4_vvc_codecs(&mpd->v.vvc, track->codecs, sizeof(track->codecs));
break;

case MOV_OBJECT_AV1:
snprintf(track->name, sizeof(track->name), "%s", "AV1");
assert(0);
return -EINVAL;

default:
assert(0);
return -EINVAL;
}

LIST_INIT_HEAD(&track->root);
track->setid = mpd->count++;
track->object = object;
track->bitrate = 0;
track->u.video.width = width;
track->u.video.height = height;
track->u.video.frame_rate = 25;
assert(((const uint8_t*)extra_data)[0] == 1); // configurationVersion
if (MOV_OBJECT_H264 == object)
{
track->u.video.avc.profile = ((const uint8_t*)extra_data)[1];
track->u.video.avc.compatibility = ((const uint8_t*)extra_data)[2];
track->u.video.avc.level = ((const uint8_t*)extra_data)[3];
}

track->seq = 1;
track->maxsize = N_FILESIZE;
Expand Down Expand Up @@ -327,6 +366,15 @@ int dash_mpd_add_audio_adaptation_set(struct dash_mpd_t* mpd, const char* prefix
assert(MOV_OBJECT_AAC == object);
track = &mpd->tracks[mpd->count];
memcpy(track->prefix, prefix, r);
if (MOV_OBJECT_AAC == object)
{
r = mpeg4_aac_audio_specific_config_load(extra_data, extra_data_size, &mpd->v.aac);
if (r <= 0)
return -EINVAL;
snprintf(track->name, sizeof(track->name), "%s", "AAC");
mpeg4_aac_codecs(&mpd->v.aac, track->codecs, sizeof(track->codecs));
}

LIST_INIT_HEAD(&track->root);
track->setid = mpd->count++;
track->object = object;
Expand Down Expand Up @@ -366,7 +414,7 @@ int dash_mpd_input(struct dash_mpd_t* mpd, int adapation, const void* data, size

track = &mpd->tracks[adapation];
if (NULL == data || 0 == bytes // flash fragment
|| ((MOV_AV_FLAG_KEYFREAME & flags) && (MOV_OBJECT_H264 == track->object || MOV_OBJECT_HEVC == track->object)))
|| ((MOV_AV_FLAG_KEYFREAME & flags) && (MOV_OBJECT_H264 == track->object || MOV_OBJECT_H265 == track->object || MOV_OBJECT_H266 == track->object || MOV_OBJECT_AV1 == track->object)))
{
r = dash_mpd_flush(mpd);

Expand Down Expand Up @@ -424,19 +472,13 @@ size_t dash_mpd_playlist(struct dash_mpd_t* mpd, char* playlist, size_t bytes)

static const char* s_h264 =
" <AdaptationSet contentType=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
" <Representation id=\"H264\" mimeType=\"video/mp4\" codecs=\"avc1.%02x%02x%02x\" width=\"%d\" height=\"%d\" frameRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4v\" initialization=\"%s-init.m4v\">\n"
" <SegmentTimeline>\n";

static const char* s_h265 =
" <AdaptationSet contentType=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
" <Representation id=\"H265\" mimeType=\"video/mp4\" codecs=\"hvc1.%02x%02x%02x\" width=\"%d\" height=\"%d\" frameRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
" <Representation id=\"%s\" mimeType=\"video/mp4\" codecs=\"%s\" width=\"%d\" height=\"%d\" frameRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4v\" initialization=\"%s-init.m4v\">\n"
" <SegmentTimeline>\n";

static const char* s_aac =
" <AdaptationSet contentType=\"audio\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n"
" <Representation id=\"AAC\" mimeType=\"audio/mp4\" codecs=\"mp4a.40.%u\" audioSamplingRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
" <Representation id=\"%s\" mimeType=\"audio/mp4\" codecs=\"%s\" audioSamplingRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
" <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\"/>\n"
" <SegmentTemplate timescale=\"1000\" media=\"%s-$Time$.m4a\" initialization=\"%s-init.m4a\">\n"
" <SegmentTimeline>\n";
Expand Down Expand Up @@ -479,19 +521,9 @@ size_t dash_mpd_playlist(struct dash_mpd_t* mpd, char* playlist, size_t bytes)
for (i = 0; i < mpd->count; i++)
{
track = &mpd->tracks[i];
if (MOV_OBJECT_H264 == track->object)
{
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, s_h264, (unsigned int)track->u.video.avc.profile, (unsigned int)track->u.video.avc.compatibility, (unsigned int)track->u.video.avc.level, track->u.video.width, track->u.video.height, track->u.video.frame_rate, track->bitrate, track->prefix, track->prefix);
list_for_each(link, &track->root)
{
seg = list_entry(link, struct dash_segment_t, link);
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, " <S t=\"%" PRId64 "\" d=\"%u\"/>\n", seg->timestamp, (unsigned int)seg->duration);
}
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, "%s", s_footer);
}
else if (MOV_OBJECT_HEVC == track->object)
if (MOV_OBJECT_H264 == track->object || MOV_OBJECT_HEVC == track->object || MOV_OBJECT_VVC == track->object)
{
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, s_h265, (unsigned int)track->u.video.avc.profile, (unsigned int)track->u.video.avc.compatibility, (unsigned int)track->u.video.avc.level, track->u.video.width, track->u.video.height, track->u.video.frame_rate, track->bitrate, track->prefix, track->prefix);
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, s_h264, track->name, track->codecs, track->u.video.width, track->u.video.height, track->u.video.frame_rate, track->bitrate, track->prefix, track->prefix);
list_for_each(link, &track->root)
{
seg = list_entry(link, struct dash_segment_t, link);
Expand All @@ -501,7 +533,7 @@ size_t dash_mpd_playlist(struct dash_mpd_t* mpd, char* playlist, size_t bytes)
}
else if (MOV_OBJECT_AAC == track->object)
{
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, s_aac, (unsigned int)track->u.audio.profile, track->u.audio.sample_rate, track->bitrate, track->u.audio.channel, track->prefix, track->prefix);
n += snprintf(playlist + n, n < bytes ? bytes - n : 0, s_aac, track->name, track->codecs, track->u.audio.sample_rate, track->bitrate, track->u.audio.channel, track->prefix, track->prefix);
list_for_each(link, &track->root)
{
seg = list_entry(link, struct dash_segment_t, link);
Expand Down
3 changes: 3 additions & 0 deletions libflv/include/mpeg4-aac.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ int mpeg4_aac_stream_mux_config_load(const uint8_t* data, size_t bytes, struct m
/// @return >=0-stream mux config length, <0-error
int mpeg4_aac_stream_mux_config_save(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);

/// @return >=0-length, <0-error
int mpeg4_aac_codecs(const struct mpeg4_aac_t* aac, char* codecs, size_t bytes);

/// get AAC profile level indication value
int mpeg4_aac_profile_level(const struct mpeg4_aac_t* aac);

Expand Down
7 changes: 7 additions & 0 deletions libflv/source/mpeg4-aac.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "mpeg4-aac.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>

int mpeg4_aac_adts_pce_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
int mpeg4_aac_adts_pce_save(uint8_t* data, size_t bytes, const struct mpeg4_aac_t* aac);
Expand Down Expand Up @@ -188,6 +189,12 @@ int mpeg4_aac_stream_mux_config_save(const struct mpeg4_aac_t* aac, uint8_t* dat
return 6;
}

int mpeg4_aac_codecs(const struct mpeg4_aac_t* aac, char* codecs, size_t bytes)
{
// https://tools.ietf.org/html/rfc6381#section-3.4
return snprintf(codecs, bytes, "mp4a.40.%u", (unsigned int)aac->profile);
}

// Table 1.6 ¨C Levels for the High Quality Audio Profile
static int mpeg4_aac_high_quality_level(const struct mpeg4_aac_t* aac)
{
Expand Down

0 comments on commit b1e08e7

Please sign in to comment.