Skip to content

Commit

Permalink
Merge pull request #29 from shiguredo/feature/add-h264-track-change-a…
Browse files Browse the repository at this point in the history
…v1-track

H.264 Track 対応 / AV1 Track の調整 / 互換性向上
  • Loading branch information
haruyama authored Sep 6, 2023
2 parents b8b2b53 + 307dc28 commit 667bfec
Show file tree
Hide file tree
Showing 15 changed files with 931 additions and 13 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ target_sources(shiguredo-mp4
src/track/track.cpp
src/track/aac.cpp
src/track/av1.cpp
src/track/h264.cpp
src/track/mp3.cpp
src/track/opus.cpp
src/track/soun.cpp
Expand Down
109 changes: 108 additions & 1 deletion example/mp4-muxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>

#include "shiguredo/mp4/brand.hpp"
#include "shiguredo/mp4/track/aac.hpp"
#include "shiguredo/mp4/track/av1.hpp"
#include "shiguredo/mp4/track/h264.hpp"
#include "shiguredo/mp4/track/mp3.hpp"
#include "shiguredo/mp4/track/opus.hpp"
#include "shiguredo/mp4/track/vpx.hpp"
Expand Down Expand Up @@ -47,10 +49,13 @@ int main(int argc, char** argv) {
app.require_subcommand(1);

std::string filename;
std::string opus_filename;

std::string vp9_filename;
std::string vp8_filename;
std::string av1_filename;
std::string h264_filename;

std::string opus_filename;
std::string mp3_filename;
std::string aac_filename;

Expand Down Expand Up @@ -91,6 +96,16 @@ int main(int argc, char** argv) {
aacvp9_faststart->add_option("--aac", aac_filename, "aac resource filename");
aacvp9_faststart->add_option("--vp9", vp9_filename, "vp9 resource filename");

auto aach264 = app.add_subcommand("aach264");
aach264->add_option("-f,--file", filename, "filename");
aach264->add_option("--aac", aac_filename, "aac resource filename");
aach264->add_option("--h264", h264_filename, "h264 resource filename");

auto aach264_faststart = app.add_subcommand("aach264_faststart");
aach264_faststart->add_option("-f,--file", filename, "filename");
aach264_faststart->add_option("--aac", aac_filename, "aac resource filename");
aach264_faststart->add_option("--h264", h264_filename, "h264 resource filename");

CLI11_PARSE(app, argc, argv);

spdlog::set_level(log_level);
Expand Down Expand Up @@ -347,6 +362,98 @@ int main(int argc, char** argv) {
writer.writeMoovBox();
writer.writeMdatHeader();
writer.copyMdatData();
} else if (subcommands[0] == aach264) {
std::vector<Resource> aac_resources;
load_resources_from_csv(&aac_resources, aac_filename);
std::vector<Resource> h264_resources;
load_resources_from_csv(&h264_resources, h264_filename);
std::ofstream ofs(filename, std::ios_base::binary);
const float duration = 15.36f;
shiguredo::mp4::writer::SimpleWriter writer(
ofs, {.mvhd_timescale = 1000,
.duration = duration,
.ftyp_params = shiguredo::mp4::box::FtypParameters{.major_brand = shiguredo::mp4::BrandIsom,
.minor_version = 0,
.compatible_brands = {
shiguredo::mp4::BrandMp41,
}}});
writer.writeFtypBox();
shiguredo::mp4::track::AACTrack aac_trak({.timescale = 48000,
.duration = duration,
.track_id = writer.getAndUpdateNextTrackID(),
.buffer_size_db = 0,
.max_bitrate = 64000,
.avg_bitrate = 64000,
.writer = &writer});
shiguredo::mp4::track::H264Track h264_trak({.timescale = 16000,
.duration = duration,
.track_id = writer.getAndUpdateNextTrackID(),
.width = 640,
.height = 240,
.writer = &writer});
for (std::size_t s = 0; s < 16; ++s) {
// chunk length: 960ms
for (std::size_t j = 0; j < 45; ++j) {
const auto i = s * 45 + j;
aac_trak.addData(aac_resources[i].timestamp, aac_resources[i].data, aac_resources[i].is_key);
}
aac_trak.terminateCurrentChunk();
for (std::size_t j = 0; j < 24; ++j) {
const auto i = s * 24 + j;
h264_trak.addData(h264_resources[i].timestamp, h264_resources[i].data, h264_resources[i].is_key);
}
h264_trak.terminateCurrentChunk();
}
writer.appendTrakAndUdtaBoxInfo({&aac_trak, &h264_trak});
writer.writeFreeBoxAndMdatHeader();
writer.writeMoovBox();
} else if (subcommands[0] == aach264_faststart) {
std::vector<Resource> aac_resources;
load_resources_from_csv(&aac_resources, aac_filename);
std::vector<Resource> h264_resources;
load_resources_from_csv(&h264_resources, h264_filename);
std::ofstream ofs(filename, std::ios_base::binary);
const float duration = 15.36f;
shiguredo::mp4::writer::FaststartWriter writer(
ofs, {.mvhd_timescale = 1000,
.duration = duration,
.ftyp_params = shiguredo::mp4::box::FtypParameters{.major_brand = shiguredo::mp4::BrandIsom,
.minor_version = 0,
.compatible_brands = {
shiguredo::mp4::BrandMp41,
}}});

writer.writeFtypBox();
shiguredo::mp4::track::AACTrack aac_trak({.timescale = 48000,
.duration = duration,
.track_id = writer.getAndUpdateNextTrackID(),
.buffer_size_db = 0,
.max_bitrate = 64000,
.avg_bitrate = 64000,
.writer = &writer});
shiguredo::mp4::track::H264Track h264_trak({.timescale = 16000,
.duration = duration,
.track_id = writer.getAndUpdateNextTrackID(),
.width = 640,
.height = 240,
.writer = &writer});
for (std::size_t s = 0; s < 16; ++s) {
// chunk length: 960 ms
for (std::size_t j = 0; j < 45; ++j) {
const auto i = s * 45 + j;
aac_trak.addData(aac_resources[i].timestamp, aac_resources[i].data, aac_resources[i].is_key);
}
aac_trak.terminateCurrentChunk();
for (std::size_t j = 0; j < 24; ++j) {
const auto i = s * 24 + j;
h264_trak.addData(h264_resources[i].timestamp, h264_resources[i].data, h264_resources[i].is_key);
}
h264_trak.terminateCurrentChunk();
}
writer.appendTrakAndUdtaBoxInfo({&aac_trak, &h264_trak});
writer.writeMoovBox();
writer.writeMdatHeader();
writer.copyMdatData();
}

return 0;
Expand Down
2 changes: 1 addition & 1 deletion include/shiguredo/mp4/box/avc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct AVCDecoderConfigurationParameters {
const std::uint8_t profile;
const std::uint8_t profile_compatibility;
const std::uint8_t level;
const std::uint8_t length_size_minus_one;
const std::uint8_t length_size_minus_one = 3;
const std::vector<AVCParameterSet> sequence_parameter_sets = {};
const std::vector<AVCParameterSet> picture_parameter_sets = {};
const bool high_profile_fields_enabled = false;
Expand Down
1 change: 1 addition & 0 deletions include/shiguredo/mp4/brand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ using Brand = std::array<std::uint8_t, 4>;
const Brand BrandIsom{'i', 's', 'o', 'm'};
const Brand BrandIso2{'i', 's', 'o', '2'};
const Brand BrandMp41{'m', 'p', '4', '1'};
const Brand BrandMp42{'m', 'p', '4', '2'};
const Brand BrandAvc1{'a', 'v', 'c', '1'};

} // namespace shiguredo::mp4
16 changes: 16 additions & 0 deletions include/shiguredo/mp4/track/av1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ struct AV1TrackParameters {
const std::uint32_t track_id = 0;
const std::uint32_t width;
const std::uint32_t height;
const std::uint8_t seq_profile = 0;
const std::uint8_t seq_level_idx_0 = 0;
const std::uint8_t seq_tier_0 = 0;
const std::uint8_t chroma_subsampling_x = 1;
const std::uint8_t chroma_subsampling_y = 1;
const std::uint8_t chroma_sample_position = 0;
const std::vector<std::uint8_t>& config_OBUs = {0xa, 0xb, 0x0, 0x0, 0x0, 0x4, 0x47,
0x7e, 0x1a, 0xff, 0xfc, 0xc0, 0x20};
shiguredo::mp4::writer::Writer* writer;
};

Expand All @@ -35,8 +43,16 @@ class AV1Track : public VideTrack {
void appendTrakBoxInfo(BoxInfo*) override;
void addData(const std::uint64_t, const std::vector<std::uint8_t>&, bool) override;
void addData(const std::uint64_t, const std::uint8_t*, const std::size_t, bool) override;
void setConfigOBUs(const std::vector<std::uint8_t>&);

private:
std::uint8_t m_seq_profile;
std::uint8_t m_seq_level_idx_0;
std::uint8_t m_seq_tier_0;
std::uint8_t m_chroma_subsampling_x;
std::uint8_t m_chroma_subsampling_y;
std::uint8_t m_chroma_sample_position;
std::vector<std::uint8_t> m_config_OBUs;
void makeStsdBoxInfo(BoxInfo*);
};

Expand Down
70 changes: 70 additions & 0 deletions include/shiguredo/mp4/track/h264.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include <cstdint>
#include <vector>

#include "shiguredo/mp4/box/avc.hpp"
#include "shiguredo/mp4/track/vide.hpp"

namespace shiguredo::mp4 {

class BoxInfo;

namespace writer {

class Writer;

}

} // namespace shiguredo::mp4

namespace shiguredo::mp4::track {

struct H264TrackParameters {
const std::uint32_t timescale;
const std::int64_t media_time = 0;
const float duration;
const std::uint32_t track_id = 0;
const std::uint32_t width;
const std::uint32_t height;
const std::uint8_t configuration_version = 0x1;
const std::uint8_t profile = box::AvcProfiles::AVCBaselineProfile;
const std::uint8_t profile_compatibility = 0xc0;
const std::uint8_t level = 31;
shiguredo::mp4::writer::Writer* writer;
};

class H264Track : public VideTrack {
public:
explicit H264Track(const H264TrackParameters&);
void appendTrakBoxInfo(BoxInfo*) override;
void addData(const std::uint64_t, const std::vector<std::uint8_t>&, bool) override;
void addData(const std::uint64_t, const std::uint8_t*, const std::size_t, bool) override;

private:
void makeStsdBoxInfo(BoxInfo*);
void appendSequenceParameterSets(const shiguredo::mp4::box::AVCParameterSet&);
void appendPictureParameterSets(const shiguredo::mp4::box::AVCParameterSet&);

std::uint8_t m_configuration_version;
std::uint8_t m_profile;
std::uint8_t m_profile_compatibility;
std::uint8_t m_level;
std::vector<shiguredo::mp4::box::AVCParameterSet> m_sequence_parameter_sets = {};
std::vector<shiguredo::mp4::box::AVCParameterSet> m_picture_parameter_sets = {};
};

struct NalUnit {
std::size_t start_code_size;
std::size_t start;
std::size_t end;
std::uint8_t header;
};

bool operator==(NalUnit const& left, NalUnit const& right);

std::ostream& operator<<(std::ostream& os, const NalUnit& nu);

NalUnit find_next_nal_unit(const std::uint8_t*, const std::size_t, const std::size_t);

} // namespace shiguredo::mp4::track
2 changes: 1 addition & 1 deletion include/shiguredo/mp4/track/soun.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace shiguredo::mp4::track {
class SounTrack : public Track {
protected:
SounTrack();
void makeTkhdBoxInfo(BoxInfo*);
void makeTkhdBoxInfo(BoxInfo*) override;
void makeSmhdBoxInfo(BoxInfo*);
};

Expand Down
2 changes: 1 addition & 1 deletion include/shiguredo/mp4/track/vide.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace shiguredo::mp4::track {
class VideTrack : public Track {
protected:
VideTrack();
void makeTkhdBoxInfo(BoxInfo*);
void makeTkhdBoxInfo(BoxInfo*) override;
void makeVmhdBoxInfo(BoxInfo*);
std::uint32_t m_width;
std::uint32_t m_height;
Expand Down
28 changes: 20 additions & 8 deletions src/track/av1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ AV1Track::AV1Track(const AV1TrackParameters& params) {
}
m_width = params.width;
m_height = params.height;
m_seq_profile = params.seq_profile;
m_seq_level_idx_0 = params.seq_level_idx_0;
m_seq_tier_0 = params.seq_tier_0;
m_chroma_subsampling_x = params.chroma_subsampling_x;
m_chroma_subsampling_y = params.chroma_subsampling_y;
m_chroma_sample_position = params.chroma_sample_position;
setConfigOBUs(params.config_OBUs);
m_writer = params.writer;
}

Expand All @@ -35,14 +42,13 @@ void AV1Track::makeStsdBoxInfo(BoxInfo* stbl) {
.height = static_cast<std::uint16_t>(m_height),
})});
new BoxInfo({.parent = av01,
.box = new box::AV1CodecConfiguration(
{.seq_profile = 0,
.seq_level_idx_0 = 0,
.seq_tier_0 = 0,
.chroma_subsampling_x = 0,
.chroma_subsampling_y = 0,
.chroma_sample_position = 0,
.config_OBUs = {0xa, 0xb, 0x0, 0x0, 0x0, 0x4, 0x47, 0x7e, 0x1a, 0xff, 0xfc, 0xc0, 0x20}})});
.box = new box::AV1CodecConfiguration({.seq_profile = m_seq_profile,
.seq_level_idx_0 = m_seq_level_idx_0,
.seq_tier_0 = m_seq_tier_0,
.chroma_subsampling_x = m_chroma_subsampling_x,
.chroma_subsampling_y = m_chroma_subsampling_y,
.chroma_sample_position = m_chroma_sample_position,
.config_OBUs = m_config_OBUs})});
}

void AV1Track::appendTrakBoxInfo(BoxInfo* moov) {
Expand Down Expand Up @@ -82,4 +88,10 @@ void AV1Track::addData(const std::uint64_t timestamp,
addMdatData(timestamp, data, data_size, is_key);
}

void AV1Track::setConfigOBUs(const std::vector<std::uint8_t>& config_OBUs) {
// configOBUs を解釈し他のパラメーターを設定するほうが好ましいが, 煩雑になるので他のパラメーターは決め打ちとしている
// https://github.com/dwbuiten/obuparse を利用してパースできる
m_config_OBUs = config_OBUs;
}

} // namespace shiguredo::mp4::track
Loading

0 comments on commit 667bfec

Please sign in to comment.