mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-01-01 15:56:59 +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>
|
||||
|
||||
* 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)
|
||||
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) ||
|
||||
(new_codec_id == MKV_V_MPEG2))
|
||||
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
|
||||
else if ((new_codec_id == MKV_S_TEXTUTF8) ||
|
||||
|
@ -99,6 +99,10 @@ xtr_oggbase_c::handle_frame(memory_cptr &frame,
|
||||
previous_end = timecode + duration;
|
||||
}
|
||||
|
||||
xtr_oggbase_c::~xtr_oggbase_c() {
|
||||
ogg_stream_clear(&os);
|
||||
}
|
||||
|
||||
void
|
||||
xtr_oggbase_c::finish_file() {
|
||||
ogg_packet op;
|
||||
@ -117,7 +121,6 @@ xtr_oggbase_c::finish_file() {
|
||||
op.granulepos = previous_end * sfreq / 1000000000;
|
||||
ogg_stream_packetin(&os, &op);
|
||||
flush_pages();
|
||||
ogg_stream_clear(&os);
|
||||
}
|
||||
|
||||
void
|
||||
@ -392,3 +395,102 @@ xtr_oggkate_c::handle_frame(memory_cptr &frame,
|
||||
|
||||
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 "kate_common.h"
|
||||
#include "theora_common.h"
|
||||
#include "xtr_base.h"
|
||||
|
||||
class xtr_flac_c: public xtr_base_c {
|
||||
@ -39,12 +40,11 @@ public:
|
||||
|
||||
public:
|
||||
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 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 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 void write_pages();
|
||||
@ -89,4 +89,22 @@ private:
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user