1/* libasf - An Advanced Systems Format media file parser 2 * Copyright (C) 2006-2010 Juho Vähä-Herttua 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include <stdlib.h> 20#include <stdio.h> 21 22#include "asf.h" 23#include "asfint.h" 24#include "byteio.h" 25#include "header.h" 26#include "parse.h" 27#include "data.h" 28#include "debug.h" 29 30 31static int 32asf_fileio_read_cb(void *stream, void *buffer, int size) 33{ 34 int ret; 35 36 ret = fread(buffer, 1, size, stream); 37 if (!ret && !feof(stream)) 38 return -1; 39 40 return ret; 41} 42 43static int64_t 44asf_fileio_seek_cb(void *stream, int64_t offset) 45{ 46 return fseek(stream, offset, SEEK_SET); 47} 48 49asf_file_t * 50asf_open_file(const char *filename) 51{ 52 asf_file_t *file; 53 asf_iostream_t stream; 54 FILE *fstream; 55 56 fstream = fopen(filename, "rb"); 57 if (!fstream) 58 return NULL; 59 60 stream.read = asf_fileio_read_cb; 61 stream.write = NULL; 62 stream.seek = asf_fileio_seek_cb; 63 stream.opaque = fstream; 64 65 file = asf_open_cb(&stream); 66 if (!file) 67 return NULL; 68 69 file->filename = filename; 70 71 return file; 72} 73 74asf_file_t * 75asf_open_cb(asf_iostream_t *iostream) 76{ 77 asf_file_t *file; 78 int i; 79 80 if (!iostream) 81 return NULL; 82 83 file = calloc(1, sizeof(asf_file_t)); 84 if (!file) 85 return NULL; 86 87 file->filename = NULL; 88 file->iostream.read = iostream->read; 89 file->iostream.write = iostream->write; 90 file->iostream.seek = iostream->seek; 91 file->iostream.opaque = iostream->opaque; 92 93 file->header = NULL; 94 file->data = NULL; 95 file->index = NULL; 96 97 for (i=0; i < ASF_MAX_STREAMS; i++) { 98 file->streams[i].type = ASF_STREAM_TYPE_NONE; 99 file->streams[i].flags = ASF_STREAM_FLAG_NONE; 100 file->streams[i].properties = NULL; 101 file->streams[i].extended_properties = NULL; 102 } 103 104 return file; 105} 106 107int 108asf_init(asf_file_t *file) 109{ 110 int tmp; 111 112 if (!file) 113 return ASF_ERROR_INTERNAL; 114 115 tmp = asf_parse_header(file); 116 if (tmp < 0) { 117 debug_printf("error parsing header: %d", tmp); 118 return tmp; 119 } 120 file->position += tmp; 121 file->data_position = file->position; 122 123 tmp = asf_parse_data(file); 124 if (tmp < 0) { 125 debug_printf("error parsing data object: %d", tmp); 126 return tmp; 127 } 128 file->position += tmp; 129 130 if (file->flags & ASF_FLAG_SEEKABLE && file->iostream.seek) { 131 int64_t seek_position; 132 133 file->index_position = file->data_position + 134 file->data->size; 135 136 seek_position = file->iostream.seek(file->iostream.opaque, 137 file->index_position); 138 139 /* if first seek fails, we can try to recover and just ignore seeking */ 140 if (seek_position >= 0) { 141 while (seek_position == file->index_position && 142 file->index_position < file->file_size && !file->index) { 143 tmp = asf_parse_index(file); 144 if (tmp < 0) { 145 debug_printf("Error finding index object! %d", tmp); 146 break; 147 } 148 149 /* The object read was something else than index */ 150 if (!file->index) 151 file->index_position += tmp; 152 153 seek_position = file->iostream.seek(file->iostream.opaque, 154 file->index_position); 155 } 156 157 if (!file->index) { 158 debug_printf("Couldn't find an index object"); 159 file->index_position = 0; 160 } 161 162 seek_position = file->iostream.seek(file->iostream.opaque, 163 file->data->packets_position); 164 if (seek_position != file->data->packets_position) { 165 /* Couldn't seek back to packets position, this is fatal! */ 166 return ASF_ERROR_SEEK; 167 } 168 } 169 } 170 171 for (tmp = 0; tmp < ASF_MAX_STREAMS; tmp++) { 172 if (file->streams[tmp].type != ASF_STREAM_TYPE_NONE) { 173 debug_printf("stream %d of type %d found!", tmp, file->streams[tmp].type); 174 } 175 } 176 177 return 0; 178} 179 180void 181asf_close(asf_file_t *file) 182{ 183 if (file) { 184 int i; 185 186 asf_free_header(file->header); 187 free(file->data); 188 if (file->index) 189 free(file->index->entries); 190 free(file->index); 191 192 if (file->filename) 193 fclose(file->iostream.opaque); 194 195 for (i=0; i < ASF_MAX_STREAMS; i++) { 196 free(file->streams[i].properties); 197 free(file->streams[i].extended_properties); 198 } 199 200 free(file); 201 } 202} 203 204asf_packet_t * 205asf_packet_create() 206{ 207 asf_packet_t *ret; 208 209 ret = malloc(sizeof(asf_packet_t)); 210 if (!ret) 211 return NULL; 212 213 asf_data_init_packet(ret); 214 215 return ret; 216} 217 218int 219asf_get_packet(asf_file_t *file, asf_packet_t *packet) 220{ 221 int tmp; 222 223 if (!file || !packet) 224 return ASF_ERROR_INTERNAL; 225 226 if (file->packet >= file->data_packets_count) { 227 return 0; 228 } 229 230 tmp = asf_data_get_packet(packet, file); 231 if (tmp < 0) { 232 return tmp; 233 } 234 235 file->position += tmp; 236 file->packet++; 237 238 return tmp; 239} 240 241void 242asf_packet_destroy(asf_packet_t *packet) 243{ 244 asf_data_free_packet(packet); 245 free(packet); 246} 247 248int64_t 249asf_seek_to_msec(asf_file_t *file, int64_t msec) 250{ 251 uint64_t packet; 252 uint64_t new_position; 253 uint64_t new_msec; 254 int64_t seek_position; 255 256 if (!file) 257 return ASF_ERROR_INTERNAL; 258 259 if (!(file->flags & ASF_FLAG_SEEKABLE) || !file->iostream.seek) { 260 return ASF_ERROR_SEEKABLE; 261 } 262 263 /* Index structure is missing, check if we can still seek */ 264 // DLM we can always seek to 0 265 if (file->index == NULL && msec > 0) { 266 int i, audiocount; 267 268 audiocount = 0; 269 for (i=0; i<ASF_MAX_STREAMS; i++) { 270 if (file->streams[i].type == ASF_STREAM_TYPE_NONE) 271 continue; 272 273 /* Non-audio files are not seekable without index */ 274 if (file->streams[i].type != ASF_STREAM_TYPE_AUDIO) 275 return ASF_ERROR_SEEKABLE; 276 else 277 audiocount++; 278 } 279 280 /* Audio files with more than one audio track are not seekable 281 * without index */ 282 if (audiocount != 1) 283 return ASF_ERROR_SEEKABLE; 284 } 285 286 if (msec > (file->play_duration / 10000)) { 287 return ASF_ERROR_SEEK; 288 } 289 290 if (file->index && file->index->entry_count == 0) { 291 // Some sort of Constant packet size? 292 293 /* Calculate current packet from index header */ 294 packet = msec * 10000 / file->index->entry_time_interval; 295 new_msec = msec; 296 297 } else if (file->index && file->index->entry_count > 0) { 298 uint32_t index_entry; 299 300 /* Fetch current packet from index entry structure */ 301 index_entry = msec * 10000 / file->index->entry_time_interval; 302 if (index_entry >= file->index->entry_count) { 303 return ASF_ERROR_SEEK; 304 } 305 packet = file->index->entries[index_entry].packet_index; 306 307 /* the correct msec time isn't known before reading the packet */ 308 new_msec = msec; 309 } else { 310 /* convert msec into bytes per second and divide with packet_size */ 311 packet = msec * file->max_bitrate / 8000 / file->packet_size; 312 313 /* calculate the resulting position in the audio stream */ 314 new_msec = packet * file->packet_size * 8000 / file->max_bitrate; 315 } 316 317 /* calculate new position to be in the beginning of the current frame */ 318 new_position = file->data->packets_position + packet * file->packet_size; 319 320 seek_position = file->iostream.seek(file->iostream.opaque, new_position); 321 if (seek_position < 0 || seek_position != new_position) { 322 return ASF_ERROR_SEEK; 323 } 324 325 /* update current file position information */ 326 file->position = new_position; 327 file->packet = packet; 328 329 return new_msec; 330} 331 332asf_metadata_t * 333asf_header_get_metadata(asf_file_t *file) 334{ 335 if (!file || !file->header) 336 return NULL; 337 338 return asf_header_metadata(file->header); 339} 340 341void 342asf_header_destroy(asf_file_t *file) 343{ 344 if (!file) 345 return; 346 347 asf_free_header(file->header); 348 file->header = NULL; 349} 350 351void 352asf_metadata_destroy(asf_metadata_t *metadata) 353{ 354 asf_header_free_metadata(metadata); 355} 356 357uint8_t 358asf_get_stream_count(asf_file_t *file) 359{ 360 uint8_t ret = 0; 361 int i; 362 363 for (i = 0; i < ASF_MAX_STREAMS; i++) { 364 if (file->streams[i].type != ASF_STREAM_TYPE_NONE) 365 ret = i; 366 } 367 368 return ret; 369} 370 371int 372asf_is_broadcast(asf_file_t *file) { 373 return (file->flags & ASF_FLAG_BROADCAST); 374} 375 376int 377asf_is_seekable(asf_file_t *file) { 378 return (file->flags & ASF_FLAG_SEEKABLE); 379} 380 381asf_stream_t * 382asf_get_stream(asf_file_t *file, uint8_t track) 383{ 384 if (!file || track >= ASF_MAX_STREAMS) 385 return NULL; 386 387 return &file->streams[track]; 388} 389 390uint64_t 391asf_get_file_size(asf_file_t *file) 392{ 393 if (!file) 394 return 0; 395 396 return file->file_size; 397} 398 399uint64_t 400asf_get_creation_date(asf_file_t *file) 401{ 402 if (!file) 403 return 0; 404 405 return file->creation_date; 406} 407 408uint64_t 409asf_get_data_packets(asf_file_t *file) 410{ 411 if (!file) 412 return 0; 413 414 return file->data_packets_count; 415} 416 417uint64_t 418asf_get_duration(asf_file_t *file) 419{ 420 if (!file) 421 return 0; 422 423 return file->play_duration; 424} 425 426uint32_t 427asf_get_max_bitrate(asf_file_t *file) 428{ 429 if (!file) 430 return 0; 431 432 return file->max_bitrate; 433} 434 435