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; }
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; }