diff options
author | Chris Robinson <[email protected]> | 2013-06-05 20:12:13 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2013-06-05 20:12:13 -0700 |
commit | 9fd87314800f27d626f25688a69587166a809dd0 (patch) | |
tree | 9ea27e551ffd80acc9b2e44c67975518a101d4fa /examples/common/alffmpeg.c | |
parent | 056fa2a47443eb40cf40eadae5721c847015813e (diff) |
Use SDL_sound for the other examples
Diffstat (limited to 'examples/common/alffmpeg.c')
-rw-r--r-- | examples/common/alffmpeg.c | 638 |
1 files changed, 0 insertions, 638 deletions
diff --git a/examples/common/alffmpeg.c b/examples/common/alffmpeg.c deleted file mode 100644 index 16f73866..00000000 --- a/examples/common/alffmpeg.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * FFmpeg Decoder Helpers - * - * Copyright (c) 2011 by Chris Robinson <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* This file contains routines for helping to decode audio using libavformat - * and libavcodec (ffmpeg). There's very little OpenAL-specific code here. */ - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <signal.h> -#include <assert.h> - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alhelpers.h" -#include "alffmpeg.h" - - -static size_t NextPowerOf2(size_t value) -{ - size_t powerOf2 = 1; - - if(value) - { - value--; - while(value) - { - value >>= 1; - powerOf2 <<= 1; - } - } - return powerOf2; -} - - -struct MemData { - char *buffer; - size_t length; - size_t pos; -}; - -static int MemData_read(void *opaque, uint8_t *buf, int buf_size) -{ - struct MemData *membuf = (struct MemData*)opaque; - int rem = membuf->length - membuf->pos; - - if(rem > buf_size) - rem = buf_size; - - memcpy(buf, &membuf->buffer[membuf->pos], rem); - membuf->pos += rem; - - return rem; -} - -static int MemData_write(void *opaque, uint8_t *buf, int buf_size) -{ - struct MemData *membuf = (struct MemData*)opaque; - int rem = membuf->length - membuf->pos; - - if(rem > buf_size) - rem = buf_size; - - memcpy(&membuf->buffer[membuf->pos], buf, rem); - membuf->pos += rem; - - return rem; -} - -static int64_t MemData_seek(void *opaque, int64_t offset, int whence) -{ - struct MemData *membuf = (struct MemData*)opaque; - - whence &= ~AVSEEK_FORCE; - switch(whence) - { - case SEEK_SET: - if(offset < 0 || (uint64_t)offset > membuf->length) - return -1; - membuf->pos = offset; - break; - - case SEEK_CUR: - if((offset >= 0 && (uint64_t)offset > membuf->length-membuf->pos) || - (offset < 0 && (uint64_t)(-offset) > membuf->pos)) - return -1; - membuf->pos += offset; - break; - - case SEEK_END: - if(offset > 0 || (uint64_t)(-offset) > membuf->length) - return -1; - membuf->pos = membuf->length + offset; - break; - - case AVSEEK_SIZE: - return membuf->length; - - default: - return -1; - } - - return membuf->pos; -} - - -struct PacketList { - AVPacket pkt; - struct PacketList *next; -}; - -struct MyStream { - AVCodecContext *CodecCtx; - int StreamIdx; - - struct PacketList *Packets; - - AVFrame *Frame; - - const uint8_t *FrameData; - size_t FrameDataSize; - - FilePtr parent; -}; - -struct MyFile { - AVFormatContext *FmtCtx; - - StreamPtr *Streams; - size_t StreamsSize; - - struct MemData membuf; -}; - - -static int done_init = 0; - -FilePtr openAVFile(const char *fname) -{ - FilePtr file; - - /* We need to make sure ffmpeg is initialized. Optionally silence warning - * output from the lib */ - if(!done_init) {av_register_all(); - av_log_set_level(AV_LOG_ERROR); - done_init = 1;} - - file = (FilePtr)calloc(1, sizeof(*file)); - if(file && avformat_open_input(&file->FmtCtx, fname, NULL, NULL) == 0) - { - /* After opening, we must search for the stream information because not - * all formats will have it in stream headers */ - if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0) - return file; - avformat_close_input(&file->FmtCtx); - } - - free(file); - return NULL; -} - -FilePtr openAVData(const char *name, char *buffer, size_t buffer_len) -{ - FilePtr file; - - if(!done_init) {av_register_all(); - av_log_set_level(AV_LOG_ERROR); - done_init = 1;} - - if(!name) - name = ""; - - file = (FilePtr)calloc(1, sizeof(*file)); - if(file && (file->FmtCtx=avformat_alloc_context()) != NULL) - { - file->membuf.buffer = buffer; - file->membuf.length = buffer_len; - file->membuf.pos = 0; - - file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, &file->membuf, - MemData_read, MemData_write, - MemData_seek); - if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0) - { - if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0) - return file; - avformat_close_input(&file->FmtCtx); - } - if(file->FmtCtx) - avformat_free_context(file->FmtCtx); - file->FmtCtx = NULL; - } - - free(file); - return NULL; -} - -FilePtr openAVCustom(const char *name, void *user_data, - int (*read_packet)(void *user_data, uint8_t *buf, int buf_size), - int (*write_packet)(void *user_data, uint8_t *buf, int buf_size), - int64_t (*seek)(void *user_data, int64_t offset, int whence)) -{ - FilePtr file; - - if(!done_init) {av_register_all(); - av_log_set_level(AV_LOG_ERROR); - done_init = 1;} - - if(!name) - name = ""; - - file = (FilePtr)calloc(1, sizeof(*file)); - if(file && (file->FmtCtx=avformat_alloc_context()) != NULL) - { - file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, user_data, - read_packet, write_packet, seek); - if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0) - { - if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0) - return file; - avformat_close_input(&file->FmtCtx); - } - if(file->FmtCtx) - avformat_free_context(file->FmtCtx); - file->FmtCtx = NULL; - } - - free(file); - return NULL; -} - - -void clearAVAudioData(StreamPtr stream) -{ - while(stream->Packets) - { - struct PacketList *self; - - self = stream->Packets; - stream->Packets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - } -} - - -void closeAVFile(FilePtr file) -{ - size_t i; - - if(!file) return; - - for(i = 0;i < file->StreamsSize;i++) - { - StreamPtr stream = file->Streams[i]; - - while(stream->Packets) - { - struct PacketList *self; - - self = stream->Packets; - stream->Packets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - } - - avcodec_close(stream->CodecCtx); - av_free(stream->Frame); - free(stream); - } - free(file->Streams); - - avformat_close_input(&file->FmtCtx); - free(file); -} - - -int getAVFileInfo(FilePtr file, int *numaudiostreams) -{ - unsigned int i; - int audiocount = 0; - - if(!file) return 1; - for(i = 0;i < file->FmtCtx->nb_streams;i++) - { - if(file->FmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - audiocount++; - } - *numaudiostreams = audiocount; - return 0; -} - -StreamPtr getAVAudioStream(FilePtr file, int streamnum) -{ - unsigned int i; - if(!file) return NULL; - for(i = 0;i < file->FmtCtx->nb_streams;i++) - { - if(file->FmtCtx->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) - continue; - - if(streamnum == 0) - { - StreamPtr stream; - AVCodec *codec; - void *temp; - size_t j; - - /* Found the requested stream. Check if a handle to this stream - * already exists and return it if it does */ - for(j = 0;j < file->StreamsSize;j++) - { - if(file->Streams[j]->StreamIdx == (int)i) - return file->Streams[j]; - } - - /* Doesn't yet exist. Now allocate a new stream object and fill in - * its info */ - stream = (StreamPtr)calloc(1, sizeof(*stream)); - if(!stream) return NULL; - - stream->parent = file; - stream->CodecCtx = file->FmtCtx->streams[i]->codec; - stream->StreamIdx = i; - - /* Try to find the codec for the given codec ID, and open it */ - codec = avcodec_find_decoder(stream->CodecCtx->codec_id); - if(!codec || avcodec_open2(stream->CodecCtx, codec, NULL) < 0) - { - free(stream); - return NULL; - } - - /* Allocate space for the decoded data to be stored in before it - * gets passed to the app */ - stream->Frame = avcodec_alloc_frame(); - if(!stream->Frame) - { - avcodec_close(stream->CodecCtx); - free(stream); - return NULL; - } - stream->FrameData = NULL; - stream->FrameDataSize = 0; - - /* Append the new stream object to the stream list. The original - * pointer will remain valid if realloc fails, so we need to use - * another pointer to watch for errors and not leak memory */ - temp = realloc(file->Streams, (file->StreamsSize+1) * - sizeof(*file->Streams)); - if(!temp) - { - avcodec_close(stream->CodecCtx); - av_free(stream->Frame); - free(stream); - return NULL; - } - file->Streams = (StreamPtr*)temp; - file->Streams[file->StreamsSize++] = stream; - return stream; - } - streamnum--; - } - return NULL; -} - -int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type) -{ - if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) - return 1; - - /* Get the sample type for OpenAL given the format detected by ffmpeg. */ - if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_U8) - *type = AL_UNSIGNED_BYTE_SOFT; - else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) - *type = AL_SHORT_SOFT; - else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S32) - *type = AL_INT_SOFT; - else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT) - *type = AL_FLOAT_SOFT; - else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_DBL) - *type = AL_DOUBLE_SOFT; - else - { - fprintf(stderr, "Unsupported ffmpeg sample format: %s\n", - av_get_sample_fmt_name(stream->CodecCtx->sample_fmt)); - return 1; - } - - /* Get the OpenAL channel configuration using the channel layout detected - * by ffmpeg. NOTE: some file types may not specify a channel layout. In - * that case, one must be guessed based on the channel count. */ - if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_MONO) - *channels = AL_MONO_SOFT; - else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) - *channels = AL_STEREO_SOFT; - else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_QUAD) - *channels = AL_QUAD_SOFT; - else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) - *channels = AL_5POINT1_SOFT; - else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1) - *channels = AL_7POINT1_SOFT; - else if(stream->CodecCtx->channel_layout == 0) - { - /* Unknown channel layout. Try to guess. */ - if(stream->CodecCtx->channels == 1) - *channels = AL_MONO_SOFT; - else if(stream->CodecCtx->channels == 2) - *channels = AL_STEREO_SOFT; - else - { - fprintf(stderr, "Unsupported ffmpeg raw channel count: %d\n", - stream->CodecCtx->channels); - return 1; - } - } - else - { - char str[1024]; - av_get_channel_layout_string(str, sizeof(str), stream->CodecCtx->channels, - stream->CodecCtx->channel_layout); - fprintf(stderr, "Unsupported ffmpeg channel layout: %s\n", str); - return 1; - } - - *rate = stream->CodecCtx->sample_rate; - - return 0; -} - - -/* Used by getAV*Data to search for more compressed data, and buffer it in the - * correct stream. It won't buffer data for streams that the app doesn't have a - * handle for. */ -static int getNextPacket(FilePtr file, int streamidx) -{ - struct PacketList *packet; - - packet = (struct PacketList*)av_malloc(sizeof(*packet)); - packet->next = NULL; - -next_packet: - while(av_read_frame(file->FmtCtx, &packet->pkt) >= 0) - { - StreamPtr *iter = file->Streams; - StreamPtr *iter_end = iter + file->StreamsSize; - - /* Check each stream the user has a handle for, looking for the one - * this packet belongs to */ - while(iter != iter_end) - { - if((*iter)->StreamIdx == packet->pkt.stream_index) - { - struct PacketList **last; - - last = &(*iter)->Packets; - while(*last != NULL) - last = &(*last)->next; - - *last = packet; - if((*iter)->StreamIdx == streamidx) - return 1; - - packet = (struct PacketList*)av_malloc(sizeof(*packet)); - packet->next = NULL; - goto next_packet; - } - iter++; - } - /* Free the packet and look for another */ - av_free_packet(&packet->pkt); - } - - av_free(packet); - return 0; -} - -uint8_t *getAVAudioData(StreamPtr stream, size_t *length) -{ - int got_frame; - int len; - - if(length) *length = 0; - - if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) - return NULL; - -next_packet: - if(!stream->Packets && !getNextPacket(stream->parent, stream->StreamIdx)) - return NULL; - - /* Decode some data, and check for errors */ - avcodec_get_frame_defaults(stream->Frame); - while((len=avcodec_decode_audio4(stream->CodecCtx, stream->Frame, - &got_frame, &stream->Packets->pkt)) < 0) - { - struct PacketList *self; - - /* Error? Drop it and try the next, I guess... */ - self = stream->Packets; - stream->Packets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - - if(!stream->Packets) - goto next_packet; - } - - if(len < stream->Packets->pkt.size) - { - /* Move the unread data to the front and clear the end bits */ - int remaining = stream->Packets->pkt.size - len; - memmove(stream->Packets->pkt.data, &stream->Packets->pkt.data[len], - remaining); - memset(&stream->Packets->pkt.data[remaining], 0, - stream->Packets->pkt.size - remaining); - stream->Packets->pkt.size -= len; - } - else - { - struct PacketList *self; - - self = stream->Packets; - stream->Packets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - } - - if(!got_frame || stream->Frame->nb_samples == 0) - goto next_packet; - - /* Set the output buffer size */ - *length = av_samples_get_buffer_size(NULL, stream->CodecCtx->channels, - stream->Frame->nb_samples, - stream->CodecCtx->sample_fmt, 1); - - return stream->Frame->data[0]; -} - -size_t readAVAudioData(StreamPtr stream, void *data, size_t length) -{ - size_t dec = 0; - - if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) - return 0; - - while(dec < length) - { - /* If there's no decoded data, find some */ - if(stream->FrameDataSize == 0) - { - stream->FrameData = getAVAudioData(stream, &stream->FrameDataSize); - if(!stream->FrameData) - break; - } - - if(stream->FrameDataSize > 0) - { - /* Get the amount of bytes remaining to be written, and clamp to - * the amount of decoded data we have */ - size_t rem = length-dec; - if(rem > stream->FrameDataSize) - rem = stream->FrameDataSize; - - /* Copy the data to the app's buffer and increment */ - if(data != NULL) - { - memcpy(data, stream->FrameData, rem); - data = (char*)data + rem; - } - dec += rem; - - /* If there's any decoded data left, move it to the front of the - * buffer for next time */ - stream->FrameData += rem; - stream->FrameDataSize -= rem; - } - } - - /* Return the number of bytes we were able to get */ - return dec; -} - -void *decodeAVAudioStream(StreamPtr stream, size_t *length) -{ - char *outbuf = NULL; - size_t buflen = 0; - void *inbuf; - size_t got; - - *length = 0; - if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) - return NULL; - - while((inbuf=getAVAudioData(stream, &got)) != NULL && got > 0) - { - void *ptr; - - ptr = realloc(outbuf, NextPowerOf2(buflen+got)); - if(ptr == NULL) - break; - outbuf = (char*)ptr; - - memcpy(&outbuf[buflen], inbuf, got); - buflen += got; - } - outbuf = (char*)realloc(outbuf, buflen); - - *length = buflen; - return outbuf; -} |