mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Support for reading AAC from Matroska files.
This commit is contained in:
parent
766d97f3b7
commit
e182f0191d
@ -1,5 +1,7 @@
|
||||
2003-05-22 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* Support for reading AAC tracks from Matroska files.
|
||||
|
||||
* Released v0.4.0.
|
||||
|
||||
2003-05-21 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
36
p_aac.cpp
36
p_aac.cpp
@ -13,7 +13,7 @@
|
||||
|
||||
/*!
|
||||
\file
|
||||
\version \$Id: p_aac.cpp,v 1.5 2003/05/20 06:30:24 mosu Exp $
|
||||
\version \$Id: p_aac.cpp,v 1.6 2003/05/22 11:11:05 mosu Exp $
|
||||
\brief AAC output module
|
||||
\author Moritz Bunkus <moritz@bunkus.org>
|
||||
*/
|
||||
@ -33,7 +33,8 @@ using namespace LIBMATROSKA_NAMESPACE;
|
||||
aac_packetizer_c::aac_packetizer_c(generic_reader_c *nreader, int nid,
|
||||
int nprofile,
|
||||
unsigned long nsamples_per_sec,
|
||||
int nchannels, track_info_t *nti)
|
||||
int nchannels, track_info_t *nti,
|
||||
bool nheaderless)
|
||||
throw (error_c): generic_packetizer_c(nreader, nti) {
|
||||
packetno = 0;
|
||||
bytes_output = 0;
|
||||
@ -43,9 +44,10 @@ aac_packetizer_c::aac_packetizer_c(generic_reader_c *nreader, int nid,
|
||||
channels = nchannels;
|
||||
id = nid;
|
||||
profile = nprofile;
|
||||
headerless = nheaderless;
|
||||
|
||||
set_track_type(track_audio);
|
||||
duplicate_data_on_add(false);
|
||||
duplicate_data_on_add(headerless);
|
||||
}
|
||||
|
||||
aac_packetizer_c::~aac_packetizer_c() {
|
||||
@ -167,23 +169,23 @@ unsigned char *aac_packetizer_c::get_aac_packet(unsigned long *header,
|
||||
}
|
||||
|
||||
void aac_packetizer_c::set_headers() {
|
||||
if (id == 0) {
|
||||
if (profile == 0)
|
||||
if (id == AAC_ID_MPEG4) {
|
||||
if (profile == AAC_PROFILE_MAIN)
|
||||
set_codec_id(MKV_A_AAC_4MAIN);
|
||||
else if (profile == 1)
|
||||
else if (profile == AAC_PROFILE_LC)
|
||||
set_codec_id(MKV_A_AAC_4LC);
|
||||
else if (profile == 2)
|
||||
else if (profile == AAC_PROFILE_SSR)
|
||||
set_codec_id(MKV_A_AAC_4SSR);
|
||||
else if (profile == 3)
|
||||
else if (profile == AAC_PROFILE_LTP)
|
||||
set_codec_id(MKV_A_AAC_4LTP);
|
||||
else
|
||||
die("aac_packetizer: Unknown AAC MPEG-4 object type...");
|
||||
} else {
|
||||
if (profile == 0)
|
||||
if (profile == AAC_PROFILE_MAIN)
|
||||
set_codec_id(MKV_A_AAC_2MAIN);
|
||||
else if (profile == 1)
|
||||
else if (profile == AAC_PROFILE_LC)
|
||||
set_codec_id(MKV_A_AAC_2LC);
|
||||
else if (profile == 2)
|
||||
else if (profile == AAC_PROFILE_SSR)
|
||||
set_codec_id(MKV_A_AAC_2SSR);
|
||||
else
|
||||
die("aac_packetizer: Unknown AAC MPEG-2 profile...");
|
||||
@ -201,6 +203,18 @@ int aac_packetizer_c::process(unsigned char *buf, int size,
|
||||
aac_header_t aacheader;
|
||||
int64_t my_timecode;
|
||||
|
||||
if (headerless) {
|
||||
if (timecode != -1)
|
||||
my_timecode = timecode;
|
||||
else
|
||||
my_timecode = (int64_t)(1000.0 * packetno * 1024 * ti->async.linear /
|
||||
samples_per_sec);
|
||||
add_packet(buf, size, my_timecode,
|
||||
(int64_t)(1000.0 * 1024 * ti->async.linear / samples_per_sec));
|
||||
|
||||
return EMOREDATA;
|
||||
}
|
||||
|
||||
if (timecode != -1)
|
||||
my_timecode = timecode;
|
||||
|
||||
|
14
p_aac.h
14
p_aac.h
@ -13,7 +13,7 @@
|
||||
|
||||
/*!
|
||||
\file
|
||||
\version \$Id: p_aac.h,v 1.5 2003/05/20 06:30:24 mosu Exp $
|
||||
\version \$Id: p_aac.h,v 1.6 2003/05/22 11:11:05 mosu Exp $
|
||||
\brief class definition for the AAC output module
|
||||
\author Moritz Bunkus <moritz@bunkus.org>
|
||||
*/
|
||||
@ -25,17 +25,27 @@
|
||||
#include "pr_generic.h"
|
||||
#include "aac_common.h"
|
||||
|
||||
#define AAC_ID_MPEG4 0
|
||||
#define AAC_ID_MPEG2 1
|
||||
|
||||
#define AAC_PROFILE_MAIN 0
|
||||
#define AAC_PROFILE_LC 1
|
||||
#define AAC_PROFILE_SSR 2
|
||||
#define AAC_PROFILE_LTP 3
|
||||
|
||||
class aac_packetizer_c: public generic_packetizer_c {
|
||||
private:
|
||||
int64_t bytes_output, packetno;
|
||||
unsigned long samples_per_sec;
|
||||
int channels, buffer_size, id, profile;
|
||||
unsigned char *packet_buffer;
|
||||
bool headerless;
|
||||
|
||||
public:
|
||||
aac_packetizer_c(generic_reader_c *nreader, int nid, int nprofile,
|
||||
unsigned long nsamples_per_sec, int nchannels,
|
||||
track_info_t *nti) throw (error_c);
|
||||
track_info_t *nti, bool nheaderless = false)
|
||||
throw (error_c);
|
||||
virtual ~aac_packetizer_c();
|
||||
|
||||
virtual int process(unsigned char *buf, int size, int64_t timecode = -1,
|
||||
|
155
r_matroska.cpp
155
r_matroska.cpp
@ -13,7 +13,7 @@
|
||||
|
||||
/*!
|
||||
\file
|
||||
\version \$Id: r_matroska.cpp,v 1.36 2003/05/21 22:17:33 mosu Exp $
|
||||
\version \$Id: r_matroska.cpp,v 1.37 2003/05/22 11:11:05 mosu Exp $
|
||||
\brief Matroska reader
|
||||
\author Moritz Bunkus <moritz@bunkus.org>
|
||||
*/
|
||||
@ -41,6 +41,7 @@ extern "C" { // for BITMAPINFOHEADER
|
||||
#include "p_mp3.h"
|
||||
#include "p_ac3.h"
|
||||
#include "p_dts.h"
|
||||
#include "p_aac.h"
|
||||
|
||||
#include "EbmlContexts.h"
|
||||
#include "EbmlHead.h"
|
||||
@ -100,9 +101,6 @@ mkv_reader_c::mkv_reader_c(track_info_t *nti) throw (error_c):
|
||||
|
||||
segment_duration = 0.0;
|
||||
|
||||
fprintf(stdout, "WARNING! Matroska files cannot be processed at the "
|
||||
"moment.\n");
|
||||
|
||||
if (!read_headers())
|
||||
throw error_c("matroska_reader: Failed to read the headers.");
|
||||
|
||||
@ -197,7 +195,8 @@ void mkv_reader_c::verify_tracks() {
|
||||
if (!strcmp(t->codec_id, MKV_V_MSCOMP)) {
|
||||
if ((t->private_data == NULL) ||
|
||||
(t->private_size < sizeof(BITMAPINFOHEADER))) {
|
||||
printf("[mkv] WARNING: CodecID for track %u is '" MKV_V_MSCOMP
|
||||
printf("matroska_reader: WARNING: CodecID for track %u is '"
|
||||
MKV_V_MSCOMP
|
||||
"', but there was no BITMAPINFOHEADER struct present. "
|
||||
"Therefore we don't have a FourCC to identify the video "
|
||||
"codec used.\n", t->tnum);
|
||||
@ -209,8 +208,8 @@ void mkv_reader_c::verify_tracks() {
|
||||
|
||||
u = get_uint32(&bih->bi_width);
|
||||
if (t->v_width != u) {
|
||||
printf("[mkv] WARNING: (MS compatibility mode, track %u) "
|
||||
"Matrosa says video width is %u, but the "
|
||||
printf("matroska_reader: WARNING: (MS compatibility mode, "
|
||||
"track %u) Matrosa says video width is %u, but the "
|
||||
"BITMAPINFOHEADER says %u.\n", t->tnum, t->v_width, u);
|
||||
if (t->v_width == 0)
|
||||
t->v_width = u;
|
||||
@ -218,9 +217,9 @@ void mkv_reader_c::verify_tracks() {
|
||||
|
||||
u = get_uint32(&bih->bi_height);
|
||||
if (t->v_height != u) {
|
||||
printf("[mkv] WARNING: (MS compatibility mode, track %u) "
|
||||
"Matrosa video height is %u, but the BITMAPINFOHEADER "
|
||||
"says %u.\n", t->tnum, t->v_height, u);
|
||||
printf("matroska_reader: WARNING: (MS compatibility mode, "
|
||||
"track %u) Matrosa video height is %u, but the "
|
||||
"BITMAPINFOHEADER says %u.\n", t->tnum, t->v_height, u);
|
||||
if (t->v_height == 0)
|
||||
t->v_height = u;
|
||||
}
|
||||
@ -228,23 +227,25 @@ void mkv_reader_c::verify_tracks() {
|
||||
memcpy(t->v_fourcc, &bih->bi_compression, 4);
|
||||
|
||||
if (t->v_frate == 0.0) {
|
||||
printf("[mkv] ERROR: (MS compatibility mode, track %u) "
|
||||
"No VideoFrameRate element was found.\n", t->tnum);
|
||||
printf("matroska_reader: ERROR: (MS compatibility mode, track "
|
||||
"%u) No VideoFrameRate element was found.\n", t->tnum);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("[mkv] Native CodecIDs for video tracks are not supported "
|
||||
"yet (track %u).\n", t->tnum);
|
||||
printf("matroska_reader: Native CodecIDs for video tracks are not "
|
||||
"supported yet (track %u).\n", t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->v_width == 0) {
|
||||
printf("[mkv] The width for track %u was not set.\n", t->tnum);
|
||||
printf("matroska_reader: The width for track %u was not set.\n",
|
||||
t->tnum);
|
||||
continue;
|
||||
}
|
||||
if (t->v_height == 0) {
|
||||
printf("[mkv] The height for track %u was not set.\n", t->tnum);
|
||||
printf("matroska_reader: The height for track %u was not set.\n",
|
||||
t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -259,10 +260,10 @@ void mkv_reader_c::verify_tracks() {
|
||||
if (!strcmp(t->codec_id, MKV_A_ACM)) {
|
||||
if ((t->private_data == NULL) ||
|
||||
(t->private_size < sizeof(WAVEFORMATEX))) {
|
||||
printf("[mkv] WARNING: CodecID for track %u is '" MKV_A_ACM "', "
|
||||
"but there was no WAVEFORMATEX struct present. "
|
||||
"Therefore we don't have a format ID to identify the audio "
|
||||
"codec used.\n", t->tnum);
|
||||
printf("matroska_reader: WARNING: CodecID for track %u is '"
|
||||
MKV_A_ACM "', but there was no WAVEFORMATEX struct present."
|
||||
" Therefore we don't have a format ID to identify the audio"
|
||||
" codec used.\n", t->tnum);
|
||||
continue;
|
||||
} else {
|
||||
t->ms_compat = 1;
|
||||
@ -270,19 +271,19 @@ void mkv_reader_c::verify_tracks() {
|
||||
wfe = (WAVEFORMATEX *)t->private_data;
|
||||
u = get_uint32(&wfe->n_samples_per_sec);
|
||||
if (((uint32_t)t->a_sfreq) != u) {
|
||||
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
|
||||
"Matroska says that there are %u samples per second, "
|
||||
"but WAVEFORMATEX says that there are %u.\n", t->tnum,
|
||||
(uint32_t)t->a_sfreq, u);
|
||||
printf("matroska_reader: WARNING: (MS compatibility mode for "
|
||||
"track %u) Matroska says that there are %u samples per "
|
||||
"second, but WAVEFORMATEX says that there are %u.\n",
|
||||
t->tnum, (uint32_t)t->a_sfreq, u);
|
||||
if (t->a_sfreq == 0.0)
|
||||
t->a_sfreq = (float)u;
|
||||
}
|
||||
|
||||
u = get_uint16(&wfe->n_channels);
|
||||
if (t->a_channels != u) {
|
||||
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
|
||||
"Matroska says that there are %u channels, but the "
|
||||
"WAVEFORMATEX says that there are %u.\n", t->tnum,
|
||||
printf("matroska_reader: WARNING: (MS compatibility mode for "
|
||||
"track %u) Matroska says that there are %u channels, but "
|
||||
"the WAVEFORMATEX says that there are %u.\n", t->tnum,
|
||||
t->a_channels, u);
|
||||
if (t->a_channels == 0)
|
||||
t->a_channels = u;
|
||||
@ -290,10 +291,10 @@ void mkv_reader_c::verify_tracks() {
|
||||
|
||||
u = get_uint16(&wfe->w_bits_per_sample);
|
||||
if (t->a_bps != u) {
|
||||
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
|
||||
"Matroska says that there are %u bits per sample, "
|
||||
"but the WAVEFORMATEX says that there are %u.\n", t->tnum,
|
||||
t->a_bps, u);
|
||||
printf("matroska_reader: WARNING: (MS compatibility mode for "
|
||||
"track %u) Matroska says that there are %u bits per "
|
||||
"sample, but the WAVEFORMATEX says that there are %u.\n",
|
||||
t->tnum, t->a_bps, u);
|
||||
if (t->a_bps == 0)
|
||||
t->a_bps = u;
|
||||
}
|
||||
@ -311,14 +312,16 @@ void mkv_reader_c::verify_tracks() {
|
||||
t->a_formattag = 0x0001;
|
||||
else if (!strcmp(t->codec_id, MKV_A_VORBIS)) {
|
||||
if (t->private_data == NULL) {
|
||||
printf("[mkv] WARNING: CodecID for track %u is 'A_VORBIS', "
|
||||
"but there are no header packets present.", t->tnum);
|
||||
printf("matroska_reader: WARNING: CodecID for track %u is "
|
||||
"'A_VORBIS', but there are no header packets present.",
|
||||
t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
c = (unsigned char *)t->private_data;
|
||||
if (c[0] != 2) {
|
||||
printf("[mkv] Vorbis track does not contain valid headers.\n");
|
||||
printf("matroska_reader: Vorbis track does not contain valid "
|
||||
"headers.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -331,7 +334,8 @@ void mkv_reader_c::verify_tracks() {
|
||||
offset++;
|
||||
}
|
||||
if (offset >= (t->private_size - 1)) {
|
||||
printf("[mkv] Vorbis track does not contain valid headers.\n");
|
||||
printf("matroska_reader: Vorbis track does not contain valid "
|
||||
"headers.\n");
|
||||
continue;
|
||||
}
|
||||
length += c[offset];
|
||||
@ -347,28 +351,37 @@ void mkv_reader_c::verify_tracks() {
|
||||
t->header_sizes[0] - t->header_sizes[1];
|
||||
|
||||
t->a_formattag = 0xFFFE;
|
||||
} else {
|
||||
printf("[mkv] Unknown/unsupported audio codec ID '%s' for track "
|
||||
"%u.\n", t->codec_id, t->tnum);
|
||||
} else if (!strcmp(t->codec_id, MKV_A_AAC_2MAIN) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_2LC) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_2SSR) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_4MAIN) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_4LC) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_4SSR) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_4LTP) ||
|
||||
!strcmp(t->codec_id, MKV_A_AAC_4SBR))
|
||||
t->a_formattag = FOURCC('M', 'P', '4', 'A');
|
||||
else {
|
||||
printf("matroska_reader: Unknown/unsupported audio codec ID '%s' "
|
||||
"for track %u.\n", t->codec_id, t->tnum);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->a_sfreq == 0.0) {
|
||||
printf("[mkv] The sampling frequency was not set for track %u.\n",
|
||||
t->tnum);
|
||||
printf("matroska_reader: The sampling frequency was not set for "
|
||||
"track %u.\n", t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->a_channels == 0) {
|
||||
printf("[mkv] The number of channels was not set for track %u.\n",
|
||||
t->tnum);
|
||||
printf("matroska_reader: The number of channels was not set for "
|
||||
"track %u.\n", t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->a_formattag == 0) {
|
||||
printf("[mkv] The audio format tag was not set for track %u.\n",
|
||||
t->tnum);
|
||||
printf("matroska_reader: The audio format tag was not set for track "
|
||||
"%u.\n", t->tnum);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -382,13 +395,13 @@ void mkv_reader_c::verify_tracks() {
|
||||
break;
|
||||
|
||||
default: // unknown track type!? error in demuxer...
|
||||
printf("[mkv] Error: matroska_reader: unknown demuxer type for track "
|
||||
"%u: '%c'\n", t->tnum, t->type);
|
||||
printf("matroska_reader: Error: matroska_reader: unknown demuxer "
|
||||
"type for track %u: '%c'\n", t->tnum, t->type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->ok)
|
||||
printf("[mkv] Track %u seems to be ok.\n", t->tnum);
|
||||
printf("matroska_reader: Track %u seems to be ok.\n", t->tnum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,7 +483,9 @@ int mkv_reader_c::read_headers() {
|
||||
fprintf(stdout, "matroska_reader: | + duration: %.3fs\n",
|
||||
segment_duration);
|
||||
|
||||
} else if (!is_ebmlvoid(l2))
|
||||
} else if (!is_ebmlvoid(l2) &&
|
||||
!(EbmlId(*l2) == KaxWritingApp::ClassInfos.GlobalId) &&
|
||||
!(EbmlId(*l2) == KaxMuxingApp::ClassInfos.GlobalId))
|
||||
fprintf(stdout, "matroska_reader: | + unknown element@2: %s\n",
|
||||
typeid(*l2).name());
|
||||
|
||||
@ -864,8 +879,7 @@ void mkv_reader_c::create_packetizers() {
|
||||
(unsigned long)t->a_sfreq,
|
||||
&nti);
|
||||
*/
|
||||
}
|
||||
else if (t->a_formattag == 0xFFFE)
|
||||
} else if (t->a_formattag == 0xFFFE)
|
||||
t->packetizer = new vorbis_packetizer_c(this,
|
||||
t->headers[0],
|
||||
t->header_sizes[0],
|
||||
@ -873,7 +887,38 @@ void mkv_reader_c::create_packetizers() {
|
||||
t->header_sizes[1],
|
||||
t->headers[2],
|
||||
t->header_sizes[2], &nti);
|
||||
else {
|
||||
else if (t->a_formattag == FOURCC('M', 'P', '4', 'A')) {
|
||||
// A_AAC/MPEG2/MAIN
|
||||
// 0123456789012345
|
||||
int id, profile;
|
||||
|
||||
if (t->codec_id[10] == '2')
|
||||
id = AAC_ID_MPEG2;
|
||||
else if (t->codec_id[10] == '4')
|
||||
id = AAC_ID_MPEG4;
|
||||
else {
|
||||
fprintf(stderr, "Error: matroska_reader: Malformed codec id "
|
||||
"%s for track %d.\n", t->codec_id, t->tnum);
|
||||
exit(1);
|
||||
}
|
||||
if (!strcmp(&t->codec_id[12], "MAIN"))
|
||||
profile = AAC_PROFILE_MAIN;
|
||||
else if (!strcmp(&t->codec_id[12], "LC"))
|
||||
profile = AAC_PROFILE_LC;
|
||||
else if (!strcmp(&t->codec_id[12], "SSR"))
|
||||
profile = AAC_PROFILE_SSR;
|
||||
else if (!strcmp(&t->codec_id[12], "LTP"))
|
||||
profile = AAC_PROFILE_LTP;
|
||||
else {
|
||||
fprintf(stderr, "Error: matroska_reader: Malformed codec id "
|
||||
"%s for track %d.\n", t->codec_id, t->tnum);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
t->packetizer = new aac_packetizer_c(this, id, profile,
|
||||
(unsigned long)t->a_sfreq,
|
||||
t->a_channels, &nti, true);
|
||||
} else {
|
||||
fprintf(stderr, "Error: matroska_reader: Unsupported track type "
|
||||
"for track %d.\n", t->tnum);
|
||||
exit(1);
|
||||
@ -995,7 +1040,8 @@ int mkv_reader_c::read() {
|
||||
|
||||
} else if (!(EbmlId(*l3) ==
|
||||
KaxBlockVirtual::ClassInfos.GlobalId))
|
||||
printf("[mkv] Uknown element@3: %s\n", typeid(*l3).name());
|
||||
printf("matroska_reader: Uknown element@3: %s\n",
|
||||
typeid(*l3).name());
|
||||
|
||||
l3->SkipData(*es, l3->Generic().Context);
|
||||
if (delete_element)
|
||||
@ -1055,7 +1101,8 @@ int mkv_reader_c::read() {
|
||||
} // while (l2 != NULL)
|
||||
} else if (!(EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) &&
|
||||
!is_ebmlvoid(l1))
|
||||
printf("[mkv] Unknown element@1: %s\n", typeid(*l1).name());
|
||||
printf("matroska_reader: Unknown element@1: %s\n",
|
||||
typeid(*l1).name());
|
||||
|
||||
if (exit_loop)
|
||||
break;
|
||||
@ -1074,7 +1121,7 @@ int mkv_reader_c::read() {
|
||||
}
|
||||
} // while (l1 != NULL)
|
||||
} catch (exception ex) {
|
||||
printf("[mkv] exception caught\n");
|
||||
printf("matroska_reader: exception caught\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
/*!
|
||||
\file
|
||||
\version \$Id: r_matroska.h,v 1.13 2003/05/20 06:30:24 mosu Exp $
|
||||
\version \$Id: r_matroska.h,v 1.14 2003/05/22 11:11:05 mosu Exp $
|
||||
\brief class definitions for the Matroska reader
|
||||
\author Moritz Bunkus <moritz@bunkus.org>
|
||||
*/
|
||||
@ -50,9 +50,8 @@ typedef struct {
|
||||
char v_fourcc[5];
|
||||
|
||||
// Parameters for audio tracks
|
||||
uint32_t a_channels, a_bps;
|
||||
uint32_t a_channels, a_bps, a_formattag;
|
||||
float a_sfreq;
|
||||
uint16_t a_formattag;
|
||||
|
||||
void *private_data;
|
||||
unsigned int private_size;
|
||||
|
Loading…
Reference in New Issue
Block a user