2 * Copyright (C) 2004-2011 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file ogg_afh_common.c Functions common to ogg/vorbis and ogg/speex. */
16 #include "ogg_afh_common.h"
19 /* Taken from decoder_example.c of libvorbis-1.2.3. */
20 static int process_packets_2_and_3(ogg_sync_state
*oss
,
21 ogg_stream_state
*stream
, struct afh_info
*afhi
,
22 struct ogg_afh_callback_info
*ci
)
30 int ret
= ogg_sync_pageout(oss
, &page
);
32 break; /* Need more data */
35 PARA_DEBUG_LOG("next input page (header/body): %lu/%lu\n",
36 page
.header_len
, page
.body_len
);
38 * We can ignore any errors here as they'll also become
39 * apparent at packetout.
41 ogg_stream_pagein(stream
, &page
);
42 PARA_DEBUG_LOG("ogg page serial: %d\n",
43 ogg_page_serialno(&page
));
45 ret
= ogg_stream_packetout(stream
, &packet
);
46 PARA_DEBUG_LOG("packet #%d: %lu bytes\n", i
+ 1,
51 return -E_STREAM_PACKETOUT
;
52 ret
= ci
->packet_callback(&packet
, i
+ 1,
53 ogg_page_serialno(&page
), afhi
,
57 if (ret
== 0) /* header complete */
66 static int process_ogg_packets(ogg_sync_state
*oss
, struct afh_info
*afhi
,
67 struct ogg_afh_callback_info
*ci
)
70 ogg_stream_state stream
;
74 if (ogg_sync_pageout(oss
, &page
) != 1)
75 return -E_SYNC_PAGEOUT
;
76 PARA_DEBUG_LOG("first input page (header/body): %lu/%lu\n",
77 page
.header_len
, page
.body_len
);
79 ret
= ogg_page_serialno(&page
);
80 ogg_stream_init(&stream
, ret
);
82 ret
= -E_STREAM_PAGEIN
;
83 if (ogg_stream_pagein(&stream
, &page
) < 0)
86 ret
= -E_STREAM_PACKETOUT
;
87 if (ogg_stream_packetout(&stream
, &packet
) != 1)
89 PARA_DEBUG_LOG("packet #0: %lu bytes\n", packet
.bytes
);
90 ret
= ci
->packet_callback(&packet
, 0, ogg_page_serialno(&page
),
91 afhi
, ci
->private_data
);
94 ret
= process_packets_2_and_3(oss
, &stream
, afhi
, ci
);
99 ogg_stream_clear(&stream
);
103 static void set_chunk_tv(int num_frames
, int num_chunks
, int frequency
,
104 struct timeval
*result
)
106 uint64_t x
= (uint64_t)num_frames
* 1000 * 1000
107 / frequency
/ num_chunks
;
109 result
->tv_sec
= x
/ 1000 / 1000;
110 result
->tv_usec
= x
% (1000 * 1000);
111 PARA_INFO_LOG("%d chunks, chunk time: %lums\n", num_chunks
,
116 * Pass first three ogg packets to callback and build the chunk table.
118 * This function extracts the first three ogg packets of the audio data
119 * given by \a map and \a numbytes and passes each packet to the callback
122 * If the packet callback indicates success and \a afhi is not \p NULL, the
123 * chunk table is built. Chunk zero contains the first three ogg packets while
124 * all other chunks consist of exactly one ogg page.
126 * \param map Audio file data.
127 * \param numbytes The length of \a map.
128 * \param afhi Passed to the packet callback, contains chunk table.
129 * \param ci The callback structure.
133 int ogg_get_file_info(char *map
, size_t numbytes
, struct afh_info
*afhi
,
134 struct ogg_afh_callback_info
*ci
)
140 int ret
, i
, j
, frames_per_chunk
, ct_size
;
141 long long unsigned num_frames
= 0;
145 buf
= ogg_sync_buffer(&oss
, len
);
148 memcpy(buf
, map
, len
);
150 if (ogg_sync_wrote(&oss
, len
) < 0)
152 ret
= process_ogg_packets(&oss
, afhi
, ci
);
157 afhi
->header_len
= oss
.returned
;
160 /* count ogg packages and get duration of the file */
161 for (i
= 0; ogg_sync_pageseek(&oss
, &op
) > 0; i
++)
162 num_frames
= ogg_page_granulepos(&op
);
163 PARA_INFO_LOG("%d pages, %llu frames\n", i
, num_frames
);
167 afhi
->seconds_total
= num_frames
/ afhi
->frequency
;
168 /* use roughly one page per chunk */
169 frames_per_chunk
= num_frames
/ i
;
170 PARA_INFO_LOG("%lu seconds, %d frames/chunk\n",
171 afhi
->seconds_total
, frames_per_chunk
);
173 afhi
->chunk_table
= para_malloc(ct_size
* sizeof(uint32_t));
174 afhi
->chunk_table
[0] = 0;
175 afhi
->chunk_table
[1] = afhi
->header_len
;
176 oss
.returned
= afhi
->header_len
;
178 for (j
= 1; ogg_sync_pageseek(&oss
, &op
) > 0; /* nothing */) {
179 int granule
= ogg_page_granulepos(&op
);
181 while (granule
> j
* frames_per_chunk
) {
185 afhi
->chunk_table
= para_realloc(
187 ct_size
* sizeof(uint32_t));
189 afhi
->chunk_table
[j
] = oss
.returned
;
192 afhi
->chunks_total
= j
;
193 set_chunk_tv(num_frames
, j
, afhi
->frequency
, &afhi
->chunk_tv
);
196 ogg_sync_clear(&oss
);