static void audioq_cleanup(struct GrooveQueue* queue, void *obj) { struct GrooveBuffer *buffer = obj; if (buffer == end_of_q_sentinel) return; struct GrooveEncoderPrivate *e = queue->context; e->audioq_size -= buffer->size; groove_buffer_unref(buffer); }
static void audioq_cleanup(struct GrooveQueue *queue, void *obj) { struct GrooveBuffer *buffer = obj; if (buffer == end_of_q_sentinel) return; struct GrooveSink *sink = queue->context; struct GrooveSinkPrivate *s = (struct GrooveSinkPrivate *) sink; s->audioq_size -= buffer->size; groove_buffer_unref(buffer); }
static void *print_thread(void *arg) { struct GrooveFingerprinterPrivate *p = (GrooveFingerprinterPrivate *)arg; struct GrooveFingerprinter *printer = &p->externals; struct GrooveBuffer *buffer; while (!p->abort_request.load()) { pthread_mutex_lock(&p->info_head_mutex); if (p->info_queue_count >= printer->info_queue_size) { pthread_cond_wait(&p->drain_cond, &p->info_head_mutex); pthread_mutex_unlock(&p->info_head_mutex); continue; } // we definitely want to unlock the mutex while we wait for the // next buffer. Otherwise there will be a deadlock when sink_flush or // sink_purge is called. pthread_mutex_unlock(&p->info_head_mutex); int result = groove_sink_buffer_get(p->sink, &buffer, 1); pthread_mutex_lock(&p->info_head_mutex); if (result == GROOVE_BUFFER_END) { // last file info emit_track_info(p); // send album info struct GrooveFingerprinterInfo *info = allocate<GrooveFingerprinterInfo>(1); if (info) { info->duration = p->album_duration; groove_queue_put(p->info_queue, info); } else { av_log(NULL, AV_LOG_ERROR, "unable to allocate album fingerprint info\n"); } p->album_duration = 0.0; p->info_head = NULL; p->info_pos = -1.0; pthread_mutex_unlock(&p->info_head_mutex); continue; } if (result != GROOVE_BUFFER_YES) { pthread_mutex_unlock(&p->info_head_mutex); break; } if (buffer->item != p->info_head) { if (p->info_head) { emit_track_info(p); } if (!chromaprint_start(p->chroma_ctx, 44100, 2)) { av_log(NULL, AV_LOG_ERROR, "unable to start fingerprint\n"); } p->track_duration = 0.0; p->info_head = buffer->item; p->info_pos = buffer->pos; } double buffer_duration = buffer->frame_count / (double)buffer->format.sample_rate; p->track_duration += buffer_duration; p->album_duration += buffer_duration; if (!chromaprint_feed(p->chroma_ctx, buffer->data[0], buffer->frame_count * 2)) { av_log(NULL, AV_LOG_ERROR, "unable to feed fingerprint\n"); } pthread_mutex_unlock(&p->info_head_mutex); groove_buffer_unref(buffer); } return NULL; }
// decode one audio packet and return its uncompressed size static int audio_decode_frame(struct GroovePlaylist *playlist, struct GrooveFile *file) { struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist; struct GrooveFilePrivate *f = (struct GrooveFilePrivate *) file; AVPacket *pkt = &f->audio_pkt; AVCodecContext *dec = f->audio_st->codec; AVPacket *pkt_temp = &p->audio_pkt_temp; *pkt_temp = *pkt; // update the audio clock with the pts if we can if (pkt->pts != AV_NOPTS_VALUE) f->audio_clock = av_q2d(f->audio_st->time_base) * pkt->pts; int max_data_size = 0; int len1, got_frame; int new_packet = 1; AVFrame *in_frame = p->in_frame; // NOTE: the audio packet can contain several frames while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) { new_packet = 0; len1 = avcodec_decode_audio4(dec, in_frame, &got_frame, pkt_temp); if (len1 < 0) { // if error, we skip the frame pkt_temp->size = 0; return -1; } pkt_temp->data += len1; pkt_temp->size -= len1; if (!got_frame) { // stop sending empty packets if the decoder is finished if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY) return 0; continue; } // push the audio data from decoded frame into the filtergraph int err = av_buffersrc_write_frame(p->abuffer_ctx, in_frame); if (err < 0) { av_strerror(err, p->strbuf, sizeof(p->strbuf)); av_log(NULL, AV_LOG_ERROR, "error writing frame to buffersrc: %s\n", p->strbuf); return -1; } // for each data format in the sink map, pull filtered audio from its // buffersink, turn it into a GrooveBuffer and then increment the ref // count for each sink in that stack. struct SinkMap *map_item = p->sink_map; double clock_adjustment = 0; while (map_item) { struct GrooveSink *example_sink = map_item->stack_head->sink; int data_size = 0; for (;;) { AVFrame *oframe = av_frame_alloc(); int err = example_sink->buffer_sample_count == 0 ? av_buffersink_get_frame(map_item->abuffersink_ctx, oframe) : av_buffersink_get_samples(map_item->abuffersink_ctx, oframe, example_sink->buffer_sample_count); if (err == AVERROR_EOF || err == AVERROR(EAGAIN)) { av_frame_free(&oframe); break; } if (err < 0) { av_frame_free(&oframe); av_log(NULL, AV_LOG_ERROR, "error reading buffer from buffersink\n"); return -1; } struct GrooveBuffer *buffer = frame_to_groove_buffer(playlist, example_sink, oframe); if (!buffer) { av_frame_free(&oframe); return -1; } data_size += buffer->size; struct SinkStack *stack_item = map_item->stack_head; // we hold this reference to avoid cleanups until at least this loop // is done and we call unref after it. groove_buffer_ref(buffer); while (stack_item) { struct GrooveSink *sink = stack_item->sink; struct GrooveSinkPrivate *s = (struct GrooveSinkPrivate *) sink; // as soon as we call groove_queue_put, this buffer could be unref'd. // so we ref before putting it in the queue, and unref if it failed. groove_buffer_ref(buffer); if (groove_queue_put(s->audioq, buffer) < 0) { av_log(NULL, AV_LOG_ERROR, "unable to put buffer in queue\n"); groove_buffer_unref(buffer); } stack_item = stack_item->next; } groove_buffer_unref(buffer); } if (data_size > max_data_size) { max_data_size = data_size; clock_adjustment = data_size / (double)example_sink->bytes_per_sec; } map_item = map_item->next; } // if no pts, then estimate it if (pkt->pts == AV_NOPTS_VALUE) f->audio_clock += clock_adjustment; return max_data_size; } return max_data_size; }
static void *encode_thread(void *arg) { struct GrooveEncoder *encoder = arg; struct GrooveEncoderPrivate *e = (struct GrooveEncoderPrivate *) encoder; struct GrooveBuffer *buffer; while (!e->abort_request) { pthread_mutex_lock(&e->encode_head_mutex); if (e->audioq_size >= encoder->encoded_buffer_size) { pthread_cond_wait(&e->drain_cond, &e->encode_head_mutex); pthread_mutex_unlock(&e->encode_head_mutex); continue; } // we definitely want to unlock the mutex while we wait for the // next buffer. Otherwise there will be a deadlock when sink_flush or // sink_purge is called. pthread_mutex_unlock(&e->encode_head_mutex); int result = groove_sink_buffer_get(e->sink, &buffer, 1); pthread_mutex_lock(&e->encode_head_mutex); if (result == GROOVE_BUFFER_END) { // flush encoder with empty packets while (encode_buffer(encoder, NULL) >= 0) {} // then flush format context with empty packets while (av_write_frame(e->fmt_ctx, NULL) == 0) {} // send trailer avio_flush(e->avio); av_log(NULL, AV_LOG_INFO, "encoder: writing trailer\n"); if (av_write_trailer(e->fmt_ctx) < 0) { av_log(NULL, AV_LOG_ERROR, "could not write trailer\n"); } avio_flush(e->avio); groove_queue_put(e->audioq, end_of_q_sentinel); cleanup_avcontext(e); init_avcontext(encoder); pthread_mutex_unlock(&e->encode_head_mutex); continue; } if (result != GROOVE_BUFFER_YES) { pthread_mutex_unlock(&e->encode_head_mutex); break; } if (!e->sent_header) { avio_flush(e->avio); // copy metadata to format context av_dict_free(&e->fmt_ctx->metadata); AVDictionaryEntry *tag = NULL; while((tag = av_dict_get(e->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { av_dict_set(&e->fmt_ctx->metadata, tag->key, tag->value, AV_DICT_IGNORE_SUFFIX); } av_log(NULL, AV_LOG_INFO, "encoder: writing header\n"); if (avformat_write_header(e->fmt_ctx, NULL) < 0) { av_log(NULL, AV_LOG_ERROR, "could not write header\n"); } avio_flush(e->avio); e->sent_header = 1; } encode_buffer(encoder, buffer); pthread_mutex_unlock(&e->encode_head_mutex); groove_buffer_unref(buffer); } return NULL; }