Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}