extract: add support for extracting AV1 to IVF

Part of the implementation of #2261.
This commit is contained in:
Moritz Bunkus 2018-10-07 22:58:32 +02:00
parent dca6f040a9
commit 3571f4ab4c
No known key found for this signature in database
GPG Key ID: 74AF00ADF2E32C85
5 changed files with 47 additions and 7 deletions

View File

@ -184,7 +184,7 @@ xtr_base_c::create_extractor(const std::string &new_codec_id,
result.reset(new xtr_mpeg1_2_video_c(new_codec_id, new_tid, tspec));
else if (new_codec_id == MKV_V_THEORA)
result.reset(new xtr_oggtheora_c(new_codec_id, new_tid, tspec));
else if ((new_codec_id == MKV_V_VP8) || (new_codec_id == MKV_V_VP9))
else if ((new_codec_id == MKV_V_VP8) || (new_codec_id == MKV_V_VP9) || (new_codec_id == MKV_V_AV1))
result.reset(new xtr_ivf_c(new_codec_id, new_tid, tspec));
// Subtitle formats

View File

@ -12,6 +12,7 @@
#include "common/common_pch.h"
#include "common/av1.h"
#include "common/codec.h"
#include "common/ebml.h"
#include "common/endian.h"
@ -21,9 +22,7 @@ xtr_ivf_c::xtr_ivf_c(const std::string &codec_id,
int64_t tid,
track_spec_t &tspec)
: xtr_base_c(codec_id, tid, tspec)
, m_frame_rate_num(0)
, m_frame_rate_den(0)
, m_frame_count(0)
, m_is_av1{codec_id == MKV_V_AV1}
{
}
@ -52,7 +51,9 @@ xtr_ivf_c::create_file(xtr_base_c *master,
"track %4% with the CodecID '%5%' is already being written to the same file.\n"))
% m_tid % m_codec_id % m_file_name % master->m_tid % master->m_codec_id);
auto fourcc = m_codec_id == MKV_V_VP8 ? "VP80" : "VP90";
auto fourcc = m_is_av1 ? "AV01"
: m_codec_id == MKV_V_VP8 ? "VP80"
: "VP90";
memcpy(m_file_header.file_magic, "DKIF", 4);
memcpy(m_file_header.fourcc, fourcc, 4);
@ -74,6 +75,8 @@ xtr_ivf_c::handle_frame(xtr_frame_t &f) {
% f.timestamp % m_frame_rate_num % m_frame_rate_den % frame_number
% (frame_number * 1000000000ull * m_frame_rate_den / m_frame_rate_num));
av1_prepend_temporal_delimiter_obu_if_needed(*f.frame);
ivf::frame_header_t frame_header;
put_uint32_le(&frame_header.frame_size, f.frame->get_size());
put_uint32_le(&frame_header.timestamp, frame_number);
@ -91,3 +94,24 @@ xtr_ivf_c::finish_file() {
m_out->setFilePointer(0);
m_out->write(&m_file_header, sizeof(m_file_header));
}
void
xtr_ivf_c::av1_prepend_temporal_delimiter_obu_if_needed(memory_c &frame) {
if (!m_is_av1 || !frame.get_size())
return;
auto type = (frame.get_buffer()[0] & 0x74) >> 3;
if (type == mtx::av1::OBU_TEMPORAL_DELIMITER)
return;
auto old_size = frame.get_size();
frame.resize(old_size + 2);
auto buffer = frame.get_buffer();
std::memmove(&buffer[2], &buffer[0], old_size);
buffer[0] = 0x12; // type = OBU_TEMPORAL_DELIMITER, extension not present, OBU size field present
buffer[1] = 0x00; // OBU size
}

View File

@ -19,9 +19,10 @@
class xtr_ivf_c: public xtr_base_c {
public:
uint64_t m_frame_rate_num, m_frame_rate_den;
uint32_t m_frame_count;
uint64_t m_frame_rate_num{}, m_frame_rate_den{};
uint32_t m_frame_count{};
ivf::file_header_t m_file_header;
bool m_is_av1{};
public:
xtr_ivf_c(const std::string &codec_id, int64_t tid, track_spec_t &tspec);
@ -33,4 +34,7 @@ public:
virtual const char *get_container_name() {
return "IVF";
};
protected:
virtual void av1_prepend_temporal_delimiter_obu_if_needed(memory_c &frame);
};

View File

@ -503,3 +503,4 @@ T_654text_subtitles_without_duration:ada9aaa1ae07ff6b20fb0618304d0820:passed:201
T_655mpeg_ts_teletext_subs_long_gap_until_end_of_display:6027ec285e5c03ec7fa84afea1d57f56:passed:20181005-212927:0.513727609
T_656mpeg_ts_bad_utf8_in_service_names2:544606778297772ea61146bdbd8f1186:passed:20181006-122753:0.020246407
T_657av1_from_mp4:08895840fd959294a31f7cbba8b2d9dd:passed:20181007-220646:0.040201275
T_658X_av1:9d2beba51aa2d3d61ddb2b82f2c94937+076ba34e5ca17057f32ad54ef12ef42c:passed:20181007-225807:0.019174721

11
tests/test-658X_av1.rb Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/ruby -w
# T_658X_av1
describe "mkvextract / AV1 to IVF"
test "extraction to IVF" do
extract "data/av1/av1.webm", 0 => "#{tmp}-1"
merge "#{tmp}-1", :output => "#{tmp}-2"
(1..2).map { |idx| hash_file("#{tmp}-#{idx}") }.join('+')
end