mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-01-04 09:15:05 +00:00
Added support for extracting Theora video tracks into Ogg files. Fix for bug 298.
This commit is contained in:
parent
8a4cd7fc44
commit
2e02c96599
@ -1,5 +1,8 @@
|
|||||||
2008-09-12 Moritz Bunkus <moritz@bunkus.org>
|
2008-09-12 Moritz Bunkus <moritz@bunkus.org>
|
||||||
|
|
||||||
|
* mkvextract: new feature: Added support for extracting Theora
|
||||||
|
video tracks into Ogg files.
|
||||||
|
|
||||||
* mkvmerge: bug fix: Fixed the frame type (key or non-key frame)
|
* mkvmerge: bug fix: Fixed the frame type (key or non-key frame)
|
||||||
detection for Theora tracks.
|
detection for Theora tracks.
|
||||||
|
|
||||||
|
@ -169,6 +169,8 @@ xtr_base_c::create_extractor(const string &new_codec_id,
|
|||||||
else if ((new_codec_id == MKV_V_MPEG1) ||
|
else if ((new_codec_id == MKV_V_MPEG1) ||
|
||||||
(new_codec_id == MKV_V_MPEG2))
|
(new_codec_id == MKV_V_MPEG2))
|
||||||
return new xtr_mpeg1_2_video_c(new_codec_id, new_tid, tspec);
|
return new xtr_mpeg1_2_video_c(new_codec_id, new_tid, tspec);
|
||||||
|
else if (new_codec_id == MKV_V_THEORA)
|
||||||
|
return new xtr_oggtheora_c(new_codec_id, new_tid, tspec);
|
||||||
|
|
||||||
// Subtitle formats
|
// Subtitle formats
|
||||||
else if ((new_codec_id == MKV_S_TEXTUTF8) ||
|
else if ((new_codec_id == MKV_S_TEXTUTF8) ||
|
||||||
|
@ -99,6 +99,10 @@ xtr_oggbase_c::handle_frame(memory_cptr &frame,
|
|||||||
previous_end = timecode + duration;
|
previous_end = timecode + duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xtr_oggbase_c::~xtr_oggbase_c() {
|
||||||
|
ogg_stream_clear(&os);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xtr_oggbase_c::finish_file() {
|
xtr_oggbase_c::finish_file() {
|
||||||
ogg_packet op;
|
ogg_packet op;
|
||||||
@ -117,7 +121,6 @@ xtr_oggbase_c::finish_file() {
|
|||||||
op.granulepos = previous_end * sfreq / 1000000000;
|
op.granulepos = previous_end * sfreq / 1000000000;
|
||||||
ogg_stream_packetin(&os, &op);
|
ogg_stream_packetin(&os, &op);
|
||||||
flush_pages();
|
flush_pages();
|
||||||
ogg_stream_clear(&os);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -392,3 +395,102 @@ xtr_oggkate_c::handle_frame(memory_cptr &frame,
|
|||||||
|
|
||||||
packetno++;
|
packetno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
xtr_oggtheora_c::xtr_oggtheora_c(const string &_codec_id,
|
||||||
|
int64_t _tid,
|
||||||
|
track_spec_t &tspec)
|
||||||
|
: xtr_oggbase_c(_codec_id, _tid, tspec)
|
||||||
|
, keyframe_number(0)
|
||||||
|
, non_keyframe_number(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtr_oggtheora_c::create_file(xtr_base_c *_master,
|
||||||
|
KaxTrackEntry &track) {
|
||||||
|
KaxCodecPrivate *priv = FINDFIRST(&track, KaxCodecPrivate);
|
||||||
|
if (NULL == priv)
|
||||||
|
mxerror("Track " LLD " with the CodecID '%s' is missing the \"codec private\" element and cannot be extracted.\n", tid, codec_id.c_str());
|
||||||
|
|
||||||
|
init_content_decoder(track);
|
||||||
|
memory_cptr mpriv = decode_codec_private(priv);
|
||||||
|
|
||||||
|
vector<memory_cptr> header_packets;
|
||||||
|
try {
|
||||||
|
header_packets = unlace_memory_xiph(mpriv);
|
||||||
|
|
||||||
|
if (header_packets.empty())
|
||||||
|
throw false;
|
||||||
|
|
||||||
|
theora_parse_identification_header(header_packets[0]->get(), header_packets[0]->get_size(), theora);
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
mxerror("Track " LLD " with the CodecID '%s' does not contain valid headers.\n", tid, codec_id.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
xtr_oggbase_c::create_file(_master, track);
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
for (packetno = 0; packetno < header_packets.size(); packetno++) {
|
||||||
|
// Handle all the header packets: ID header, comments, etc
|
||||||
|
op.b_o_s = (0 == packetno ? 1 : 0);
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.packetno = packetno;
|
||||||
|
op.packet = header_packets[packetno]->get();
|
||||||
|
op.bytes = header_packets[packetno]->get_size();
|
||||||
|
op.granulepos = 0;
|
||||||
|
ogg_stream_packetin(&os, &op);
|
||||||
|
|
||||||
|
if (0 == packetno) /* ID header must be alone on a separate page */
|
||||||
|
flush_pages();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush at last header, data must start on a new page */
|
||||||
|
flush_pages();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtr_oggtheora_c::handle_frame(memory_cptr &frame,
|
||||||
|
KaxBlockAdditions *additions,
|
||||||
|
int64_t timecode,
|
||||||
|
int64_t duration,
|
||||||
|
int64_t bref,
|
||||||
|
int64_t fref,
|
||||||
|
bool keyframe,
|
||||||
|
bool discardable,
|
||||||
|
bool references_valid) {
|
||||||
|
content_decoder.reverse(frame, CONTENT_ENCODING_SCOPE_BLOCK);
|
||||||
|
|
||||||
|
if (frame->get_size() && (0x00 == (frame->get()[0] & 0x40))) {
|
||||||
|
keyframe = true;
|
||||||
|
keyframe_number += non_keyframe_number + 1;
|
||||||
|
non_keyframe_number = 0;
|
||||||
|
|
||||||
|
} else
|
||||||
|
non_keyframe_number += 1;
|
||||||
|
|
||||||
|
ogg_packet op;
|
||||||
|
|
||||||
|
op.b_o_s = 0;
|
||||||
|
op.e_o_s = 0;
|
||||||
|
op.packetno = packetno;
|
||||||
|
op.packet = frame->get();
|
||||||
|
op.bytes = frame->get_size();
|
||||||
|
op.granulepos = (keyframe_number << theora.kfgshift) | (non_keyframe_number & ((1 << theora.kfgshift) - 1));
|
||||||
|
|
||||||
|
ogg_stream_packetin(&os, &op);
|
||||||
|
write_pages();
|
||||||
|
|
||||||
|
packetno++;
|
||||||
|
|
||||||
|
// mxinfo("Theora kfgshift %d granulepos 0x%08x %08x keyframe_number " LLD " non_keyframe_number " LLD "%s size %d\n",
|
||||||
|
// theora.kfgshift, (uint32_t)(op.granulepos >> 32), (uint32_t)(op.granulepos & 0xffffffff), keyframe_number, non_keyframe_number, keyframe ? " key" : "",
|
||||||
|
// frame->get_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xtr_oggtheora_c::finish_file() {
|
||||||
|
flush_pages();
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <ogg/ogg.h>
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
#include "kate_common.h"
|
#include "kate_common.h"
|
||||||
|
#include "theora_common.h"
|
||||||
#include "xtr_base.h"
|
#include "xtr_base.h"
|
||||||
|
|
||||||
class xtr_flac_c: public xtr_base_c {
|
class xtr_flac_c: public xtr_base_c {
|
||||||
@ -39,12 +40,11 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
xtr_oggbase_c(const string &_codec_id, int64_t _tid, track_spec_t &tspec);
|
xtr_oggbase_c(const string &_codec_id, int64_t _tid, track_spec_t &tspec);
|
||||||
|
virtual ~xtr_oggbase_c();
|
||||||
|
|
||||||
virtual void create_file(xtr_base_c *_master, KaxTrackEntry &track);
|
virtual void create_file(xtr_base_c *_master, KaxTrackEntry &track);
|
||||||
virtual void handle_frame(memory_cptr &frame, KaxBlockAdditions *additions,
|
virtual void handle_frame(memory_cptr &frame, KaxBlockAdditions *additions, int64_t timecode, int64_t duration, int64_t bref,
|
||||||
int64_t timecode, int64_t duration, int64_t bref,
|
int64_t fref, bool keyframe, bool discardable, bool references_valid);
|
||||||
int64_t fref, bool keyframe, bool discardable,
|
|
||||||
bool references_valid);
|
|
||||||
virtual void finish_file();
|
virtual void finish_file();
|
||||||
|
|
||||||
virtual void write_pages();
|
virtual void write_pages();
|
||||||
@ -89,4 +89,22 @@ private:
|
|||||||
kate_identification_header_t kate_id_header;
|
kate_identification_header_t kate_id_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class xtr_oggtheora_c: public xtr_oggbase_c {
|
||||||
|
public:
|
||||||
|
xtr_oggtheora_c(const string &_codec_id, int64_t _tid, track_spec_t &tspec);
|
||||||
|
|
||||||
|
virtual void create_file(xtr_base_c *_master, KaxTrackEntry &track);
|
||||||
|
virtual void handle_frame(memory_cptr &frame, KaxBlockAdditions *additions, int64_t timecode, int64_t duration, int64_t bref,
|
||||||
|
int64_t fref, bool keyframe, bool discardable, bool references_valid);
|
||||||
|
virtual void finish_file();
|
||||||
|
|
||||||
|
virtual const char *get_container_name() {
|
||||||
|
return "Ogg (Theora in Ogg)";
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
theora_identification_header_t theora;
|
||||||
|
int64_t keyframe_number, non_keyframe_number;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user