int groove_sink_attach(struct GrooveSink *sink, struct GroovePlaylist *playlist) { struct GrooveSinkPrivate *s = (struct GrooveSinkPrivate *) sink; // cache computed audio format stuff int channel_count = av_get_channel_layout_nb_channels(sink->audio_format.channel_layout); int bytes_per_frame = channel_count * av_get_bytes_per_sample((enum AVSampleFormat)sink->audio_format.sample_fmt); sink->bytes_per_sec = bytes_per_frame * sink->audio_format.sample_rate; s->min_audioq_size = sink->buffer_size * bytes_per_frame; av_log(NULL, AV_LOG_INFO, "audio queue size: %d\n", s->min_audioq_size); // add the sink to the entry that matches its audio format struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist; pthread_mutex_lock(&p->decode_head_mutex); int err = add_sink_to_map(playlist, sink); pthread_cond_signal(&p->sink_drain_cond); pthread_mutex_unlock(&p->decode_head_mutex); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to attach device: out of memory\n"); return err; } // in case we've called abort on the queue, reset groove_queue_reset(s->audioq); sink->playlist = playlist; return 0; }
int groove_fingerprinter_attach(struct GrooveFingerprinter *printer, struct GroovePlaylist *playlist) { struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer; printer->playlist = playlist; groove_queue_reset(p->info_queue); p->chroma_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); if (!p->chroma_ctx) { groove_fingerprinter_detach(printer); return GrooveErrorNoMem; } int err; if ((err = groove_sink_attach(p->sink, playlist))) { groove_fingerprinter_detach(printer); return err; } if (pthread_create(&p->thread_id, NULL, print_thread, printer)) { groove_fingerprinter_detach(printer); return GrooveErrorSystemResources; } return 0; }
int groove_encoder_attach(struct GrooveEncoder *encoder, struct GroovePlaylist *playlist) { struct GrooveEncoderPrivate *e = (struct GrooveEncoderPrivate *) encoder; encoder->playlist = playlist; groove_queue_reset(e->audioq); e->oformat = av_guess_format(encoder->format_short_name, encoder->filename, encoder->mime_type); if (!e->oformat) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to determine format\n"); return -1; } // av_guess_codec ignores mime_type, filename, and codec_short_name. see // https://trac.ffmpeg.org/ticket/4706 // because of this we do a workaround to return the correct codec based on // the codec_short_name. AVCodec *codec = NULL; if (encoder->codec_short_name) { codec = avcodec_find_encoder_by_name(encoder->codec_short_name); if (!codec) { const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(encoder->codec_short_name); if (desc) { codec = avcodec_find_encoder(desc->id); } } } if (!codec) { enum AVCodecID codec_id = av_guess_codec(e->oformat, encoder->codec_short_name, encoder->filename, encoder->mime_type, AVMEDIA_TYPE_AUDIO); codec = avcodec_find_encoder(codec_id); if (!codec) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to find encoder\n"); return -1; } } e->codec = codec; av_log(NULL, AV_LOG_INFO, "encoder: using codec: %s\n", codec->long_name); encoder->actual_audio_format.sample_fmt = closest_supported_sample_fmt( codec, encoder->target_audio_format.sample_fmt); encoder->actual_audio_format.sample_rate = closest_supported_sample_rate( codec, encoder->target_audio_format.sample_rate); encoder->actual_audio_format.channel_layout = closest_supported_channel_layout( codec, encoder->target_audio_format.channel_layout); log_audio_fmt(&encoder->actual_audio_format); int err = init_avcontext(encoder); if (err < 0) { groove_encoder_detach(encoder); return err; } e->sink->audio_format = encoder->actual_audio_format; e->sink->buffer_size = encoder->sink_buffer_size; e->sink->buffer_sample_count = (codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) ? 0 : e->stream->codec->frame_size; e->sink->gain = encoder->gain; if (groove_sink_attach(e->sink, playlist) < 0) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n"); return -1; } if (pthread_create(&e->thread_id, NULL, encode_thread, encoder) != 0) { groove_encoder_detach(encoder); av_log(NULL, AV_LOG_ERROR, "unable to create encoder thread\n"); return -1; } return 0; }