1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
#include "mkv_theora_decoder.h"
#include "../nsmkv/Lacing.h"
#include "../nsmkv/Cluster.h"
#include <mmsystem.h>
int MKVDecoder::CreateVideoDecoder(const char *codec_id, const nsmkv::TrackEntryData *track_entry_data, const nsmkv::VideoData *video_data, ifc_mkvvideodecoder **decoder)
{
if (!strcmp(codec_id, "V_THEORA"))
{
MKVTheora *theora = new MKVTheora(video_data);
nsmkv::LacingState lacing_state;
if (nsmkv::Lacing::GetState(nsmkv::BlockBinary::XIPH_LACING, (const uint8_t *)track_entry_data->codec_private, track_entry_data->codec_private_len, &lacing_state))
{
const uint8_t *frame;
size_t frame_len;
uint16_t frame_number=0;
while (nsmkv::Lacing::GetFrame(frame_number, (const uint8_t *)track_entry_data->codec_private, track_entry_data->codec_private_len, &frame, &frame_len, &lacing_state))
{
ogg_packet packet = {const_cast<uint8_t *>(frame), (long)frame_len, (frame_number==0), 0, 0 /*-1?*/, theora->packet_number++};
int ret = th_decode_headerin(&theora->info, &theora->comment, &theora->setup, &packet);
if (ret < 0)
goto bail;
frame_number++;
}
theora->decoder = th_decode_alloc(&theora->info, theora->setup);
if (!theora->decoder)
goto bail;
*decoder = theora;
return CREATEDECODER_SUCCESS;
}
bail:
delete theora;
return CREATEDECODER_FAILURE;
}
else
{
return CREATEDECODER_NOT_MINE;
}
}
#define CBCLASS MKVDecoder
START_DISPATCH;
CB(CREATE_VIDEO_DECODER, CreateVideoDecoder)
END_DISPATCH;
#undef CBCLASS
MKVTheora::MKVTheora(const nsmkv::VideoData *video_data) : video_data(video_data)
{
th_info_init(&info);
memset(&comment, 0, sizeof(comment));
setup=0;
packet_number=0;
frame_ready=false;
flushing=false;
}
int MKVTheora::GetOutputProperties(int *x, int *y, int *color_format, double *aspect_ratio)
{
if (decoder)
{
th_ycbcr_buffer buffer;
if (th_decode_ycbcr_out(decoder, buffer) == 0)
{
*x = buffer[0].width;
*y = buffer[0].height;
*aspect_ratio=1.0;
*color_format = mmioFOURCC('Y','V','1','2');
return MKV_SUCCESS;
}
}
return MKV_FAILURE;
}
int MKVTheora::DecodeBlock(const void *inputBuffer, size_t inputBufferBytes, uint64_t timestamp)
{
if (decoder)
{
ogg_packet packet = {(uint8_t *)inputBuffer, (long)inputBufferBytes, 0, 0, 0 -1, packet_number++};
if (flushing)
{
if (th_packet_iskeyframe(&packet))
{
flushing=false;
}
else
return MKV_FAILURE;
}
if (th_decode_packetin(decoder, &packet, 0) == 0)
frame_ready=true;
last_timestamp=timestamp;
return MKV_SUCCESS;
}
return MKV_FAILURE;
}
void MKVTheora::Flush()
{
packet_number = 0;
flushing=true;
}
int MKVTheora::GetPicture(void **data, void **decoder_data, uint64_t *timestamp)
{
if (decoder && frame_ready)
{
th_ycbcr_buffer buffer;
if (th_decode_ycbcr_out(decoder, buffer) == 0)
{
planes.y.baseAddr = buffer[0].data;
planes.y.rowBytes = buffer[0].stride;
planes.u.baseAddr = buffer[1].data;
planes.u.rowBytes = buffer[1].stride;
planes.v.baseAddr = buffer[2].data;
planes.v.rowBytes = buffer[2].stride;
*data = &planes;
*decoder_data = 0;
*timestamp = last_timestamp;
frame_ready = false;
return MKV_SUCCESS;
}
}
return MKV_FAILURE;
}
void MKVTheora::FreePicture(void *data, void *decoder_data)
{
}
void MKVTheora::HurryUp(int state)
{
}
void MKVTheora::Close()
{
if (decoder)
th_decode_free(decoder);
delete this;
}
#define CBCLASS MKVTheora
START_DISPATCH;
CB(GET_OUTPUT_PROPERTIES, GetOutputProperties)
CB(DECODE_BLOCK, DecodeBlock)
VCB(FLUSH, Flush)
CB(GET_PICTURE, GetPicture)
VCB(FREE_PICTURE, FreePicture)
VCB(HURRY_UP, HurryUp)
VCB(CLOSE, Close)
END_DISPATCH;
#undef CBCLASS
|