Esempio n. 1
0
static void sink_flush(struct GrooveSink *sink) {
    struct GrooveEncoder *encoder = sink->userdata;
    struct GrooveEncoderPrivate *e = (struct GrooveEncoderPrivate *) encoder;

    pthread_mutex_lock(&e->encode_head_mutex);
    groove_queue_flush(e->audioq);

    cleanup_avcontext(e);
    init_avcontext(encoder);
    groove_queue_put(e->audioq, end_of_q_sentinel);

    pthread_cond_signal(&e->drain_cond);
    pthread_mutex_unlock(&e->encode_head_mutex);
}
Esempio n. 2
0
static int encoder_write_packet(void *opaque, uint8_t *buf, int buf_size) {
    struct GrooveEncoderPrivate *e = opaque;

    struct GrooveBufferPrivate *b = av_mallocz(sizeof(struct GrooveBufferPrivate));

    if (!b) {
        av_log(NULL, AV_LOG_ERROR, "unable to allocate buffer\n");
        return -1;
    }

    struct GrooveBuffer *buffer = &b->externals;

    if (pthread_mutex_init(&b->mutex, NULL) != 0) {
        av_free(b);
        av_log(NULL, AV_LOG_ERROR, "unable to create mutex\n");
        return -1;
    }

    buffer->item = e->encode_head;
    buffer->pos = e->encode_pos;
    buffer->pts = e->encode_pts;
    buffer->format = e->encode_format;

    b->is_packet = 1;
    b->data = av_malloc(buf_size);
    if (!b->data) {
        av_free(buffer);
        av_free(b);
        pthread_mutex_destroy(&b->mutex);
        av_log(NULL, AV_LOG_ERROR, "unable to create data buffer\n");
        return -1;
    }
    memcpy(b->data, buf, buf_size);

    buffer->data = &b->data;
    buffer->size = buf_size;

    b->ref_count = 1;

    groove_queue_put(e->audioq, buffer);

    return 0;
}
Esempio n. 3
0
static int emit_track_info(struct GrooveFingerprinterPrivate *p) {
    struct GrooveFingerprinterInfo *info = allocate<GrooveFingerprinterInfo>(1);
    if (!info) {
        return GrooveErrorNoMem;
    }
    info->item = p->info_head;
    info->duration = p->track_duration;

    if (!chromaprint_finish(p->chroma_ctx)) {
        av_log(NULL, AV_LOG_ERROR, "unable to finish chromaprint\n");
        return GrooveErrorNoMem;
    }
    if (!chromaprint_get_raw_fingerprint(p->chroma_ctx,
                (void**)&info->fingerprint, &info->fingerprint_size))
    {
        av_log(NULL, AV_LOG_ERROR, "unable to get fingerprint\n");
        return GrooveErrorNoMem;
    }

    groove_queue_put(p->info_queue, info);

    return 0;
}
Esempio n. 4
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. 5
0
static int sink_signal_end(struct GrooveSink *sink) {
    struct GrooveSinkPrivate *s = (struct GrooveSinkPrivate *) sink;
    groove_queue_put(s->audioq, end_of_q_sentinel);
    return 0;
}
Esempio n. 6
0
// 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;
}
Esempio n. 7
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;
}