libspectrum_error libspectrum_csw_write( libspectrum_byte **buffer, size_t *length, libspectrum_tape *tape ) { libspectrum_error error; libspectrum_dword sample_rate; size_t length_offset; libspectrum_byte *ptr = *buffer; size_t signature_length = strlen( csw_signature ); /* First, write the .csw signature and the rest of the header */ libspectrum_make_room( buffer, signature_length + 29, &ptr, length ); memcpy( ptr, csw_signature, signature_length ); ptr += signature_length; *ptr++ = 2; /* Major version number */ *ptr++ = 0; /* Minor version number */ /* sample rate */ sample_rate = find_sample_rate( tape ); libspectrum_write_dword( &ptr, sample_rate ); /* Store where the total number of pulses (after decompression) will be written, and skip over those bytes */ length_offset = ptr - *buffer; ptr += sizeof(libspectrum_dword); /* compression type */ #ifdef HAVE_ZLIB_H *ptr++ = 2; /* Z-RLE */ #else *ptr++ = 1; /* RLE */ #endif /* flags */ *ptr++ = 0; /* No flags */ /* header extension length in bytes */ *ptr++ = 0; /* No header extension */ /* encoding application description */ memset( ptr, 0, 16 ); ptr += 16; /* No creator for now */ /* header extension data is zero so on to the data */ error = csw_write_body( buffer, length, tape, sample_rate, length_offset, ptr ); if( error != LIBSPECTRUM_ERROR_NONE ) return error; return LIBSPECTRUM_ERROR_NONE; }
bool stream_transcode(stream_t *stream, codec_type_t codec_type, int bitrate) { int result; enum AVCodecID dst_codec_id; AVCodec *dst_codec = NULL; AVCodecContext *decoder = NULL, *encoder = NULL; enum AVSampleFormat dst_sample_fmt; int dst_sample_rate; resampler_t *resampler = NULL; if (codec_type == CODEC_TYPE_MP3) { dst_codec_id = AV_CODEC_ID_MP3; } else if (codec_type == CODEC_TYPE_OGG_VORBIS) { dst_codec_id = AV_CODEC_ID_VORBIS; } else if (codec_type == CODEC_TYPE_FLAC) { dst_codec_id = AV_CODEC_ID_FLAC; } else if (codec_type == CODEC_TYPE_AAC) { dst_codec_id = AV_CODEC_ID_AAC; } else if (codec_type == CODEC_TYPE_OPUS) { dst_codec_id = AV_CODEC_ID_OPUS; } else { musicd_log(LOG_ERROR, "stream", "unsupported encoder requested"); return false;; } dst_codec = avcodec_find_encoder(dst_codec_id); if (!dst_codec) { musicd_log(LOG_ERROR, "stream", "requested encoder not found"); return false; } decoder = stream->src_ctx->streams[0]->codec; /* Try to figure out common sample format to skip format conversion */ decoder->request_sample_fmt = find_common_sample_fmt(stream->src_codec->sample_fmts, dst_codec->sample_fmts); result = avcodec_open2(decoder, stream->src_codec, NULL); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open decoder: %s", strerror(AVUNERROR(result))); goto fail; } dst_sample_fmt = find_sample_fmt(decoder->sample_fmt, dst_codec->sample_fmts); dst_sample_rate = find_sample_rate(decoder->sample_rate, dst_codec->supported_samplerates); /** @todo FIXME Hard-coded values. */ if (bitrate < 64000 || bitrate > 320000) { bitrate = 196000; } if (decoder->channel_layout == 0) { decoder->channel_layout = av_get_default_channel_layout(decoder->channels); } encoder = avcodec_alloc_context3(dst_codec); encoder->sample_rate = dst_sample_rate; encoder->channels = decoder->channels; encoder->sample_fmt = dst_sample_fmt; encoder->channel_layout = decoder->channel_layout; encoder->bit_rate = bitrate; result = avcodec_open2(encoder, dst_codec, NULL); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open encoder: %s", strerror(AVUNERROR(result))); goto fail; } if (decoder->channel_layout != encoder->channel_layout || decoder->sample_fmt != encoder->sample_fmt || decoder->sample_rate != encoder->sample_rate) { resampler = resampler_alloc(); av_opt_set_int(resampler, "in_channel_layout", decoder->channel_layout, 0); av_opt_set_int(resampler, "out_channel_layout", encoder->channel_layout, 0); av_opt_set_int(resampler, "in_sample_rate", decoder->sample_rate, 0); av_opt_set_int(resampler, "out_sample_rate", encoder->sample_rate, 0); av_opt_set_int(resampler, "in_sample_fmt", decoder->sample_fmt, 0); av_opt_set_int(resampler, "out_sample_fmt", encoder->sample_fmt, 0); result = resampler_init(resampler); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open resampler: %s", strerror(AVUNERROR(result))); goto fail; } musicd_log(LOG_DEBUG, "stream", "resample: ch:%d(%d) rate:%d fmt:%d -> ch:%d(%d) rate:%d fmt:%d", decoder->channel_layout, decoder->channels, decoder->sample_rate, decoder->sample_fmt, encoder->channel_layout, encoder->channels, encoder->sample_rate, encoder->sample_fmt); } stream->decoder = decoder; stream->encoder = encoder; stream->dst_codec = dst_codec; stream->dst_codec_type = codec_type; stream->resampler = resampler; format_from_av(encoder, &stream->format); stream->src_buf = av_audio_fifo_alloc(encoder->sample_fmt, encoder->channels, encoder->frame_size); stream->decode_frame = avcodec_alloc_frame(); if (stream->resampler) { /* The buffer will be allocated dynamically */ stream->resample_frame = avcodec_alloc_frame(); } int buf_size = av_samples_get_buffer_size(NULL, stream->encoder->channels, stream->encoder->frame_size, stream->encoder->sample_fmt, 0); stream->encode_buf = av_mallocz(buf_size); stream->encode_frame = avcodec_alloc_frame(); stream->encode_frame->nb_samples = stream->encoder->frame_size; avcodec_fill_audio_frame(stream->encode_frame, stream->encoder->channels, stream->encoder->sample_fmt, stream->encode_buf, buf_size, 0); return true; fail: if (decoder) { avcodec_close(decoder); } if (encoder) { avcodec_close(encoder); av_free(encoder); } if (resampler) { resampler_free(&resampler); } return false; }