#include "transcode.h" #include "resample.h" #include void transcode(GInputStream *input, const struct decoder_plugin *_decoder, GOutputStream *output, const struct encoder_plugin *_encoder) { GError *error = NULL; gboolean decode_done = FALSE, encode_done = FALSE; struct decoder *decoder = g_new0(struct decoder, 1); struct encoder *encoder = g_new0(struct encoder, 1); decoder->decoder = _decoder; encoder->encoder = _encoder; decoder_init(decoder); encoder_init(encoder); /* holds decoded audio passed to encoder */ GInputStream *decoded_in = g_memory_input_stream_new(); SRC_STATE *state = NULL; while(decode_done == FALSE || encode_done == FALSE) { /* holds decoded audio from decoder */ GOutputStream *decoded_out = g_memory_output_stream_new(NULL, 0, g_realloc, g_free); if(decode_done == FALSE && decoder_decode(decoder, input, decoded_out, &error) <= 0 && error != NULL) { if(error->code == DECODER_CODE_DONE) { decode_done = TRUE; } else { g_warning(error->message); g_object_unref(decoded_out); break; } g_error_free(error); error = NULL; } /* temp variables */ gpointer data = g_memory_output_stream_get_data((GMemoryOutputStream*)decoded_out); gsize size = g_memory_output_stream_get_data_size((GMemoryOutputStream*)decoded_out); if(size > 0) { /* TODO: allow custom sample rate */ if(decoder->rate != 44100) { if(state == NULL) { state = resample_init(decoder->channels, &error); /* state should be NULL in case of errors */ if(error) { g_warning(error->message); break; } } gpointer out_data; gsize out_size; resample(state, decoder->rate, 44100, decoder->channels, data, size, &out_data, &out_size, decode_done, &error); if(error) { g_warning(error->message); g_error_free(error); error = NULL; } /* data is owned by decoded_out, don't free */ data = out_data; size = out_size; } else { data = g_memdup(data, size); } g_memory_input_stream_add_data((GMemoryInputStream*)decoded_in, data, size, g_free); } g_object_unref(decoded_out); if(encode_done == FALSE && encoder_encode(encoder, decoded_in, output, &error) <= 0 && error != NULL) { if(error->code == ENCODER_CODE_DONE) { /* assume the encoder doesn't have enough data to continue * if the decoder isn't done yet */ encode_done = decode_done; if(encode_done == TRUE) { encoder_flush(encoder, output, &error); } } else { g_warning(error->message); break; } g_error_free(error); error = NULL; } } g_debug("transcoding done"); /* error cleanup */ if(error) { g_error_free(error); } /* resample cleanup */ if(state) { resample_free(state); } g_object_unref(decoded_in); decoder_close(decoder); encoder_close(encoder); g_free(decoder); g_free(encoder); }