static void ffmmal_stop_decoder(AVCodecContext *avctx) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_BUFFER_HEADER_T *buffer; mmal_port_disable(decoder->input[0]); mmal_port_disable(decoder->output[0]); mmal_port_disable(decoder->control); mmal_port_flush(decoder->input[0]); mmal_port_flush(decoder->output[0]); mmal_port_flush(decoder->control); while ((buffer = mmal_queue_get(ctx->queue_decoded_frames))) mmal_buffer_header_release(buffer); while (ctx->waiting_buffers) { FFBufferEntry *buffer = ctx->waiting_buffers; ctx->waiting_buffers = buffer->next; if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) avpriv_atomic_int_add_and_fetch(&ctx->packets_buffered, -1); av_buffer_unref(&buffer->ref); av_free(buffer); } ctx->waiting_buffers_tail = NULL; av_assert0(avpriv_atomic_int_get(&ctx->packets_buffered) == 0); ctx->frames_output = ctx->eos_received = ctx->eos_sent = ctx->packets_sent = ctx->extradata_sent = 0; }
static void ffmmal_poolref_unref(FFPoolRef *ref) { if (ref && avpriv_atomic_int_add_and_fetch(&ref->refcount, -1) == 0) { mmal_pool_destroy(ref->pool); av_free(ref); } }
// Setup frame with a new reference to buffer. The buffer must have been // allocated from the given pool. static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool, MMAL_BUFFER_HEADER_T *buffer) { FFBufferRef *ref = av_mallocz(sizeof(*ref)); if (!ref) return AVERROR(ENOMEM); ref->pool = pool; ref->buffer = buffer; frame->buf[0] = av_buffer_create((void *)ref, sizeof(*ref), ffmmal_release_frame, NULL, AV_BUFFER_FLAG_READONLY); if (!frame->buf[0]) { av_free(ref); return AVERROR(ENOMEM); } avpriv_atomic_int_add_and_fetch(&ref->pool->refcount, 1); mmal_buffer_header_acquire(buffer); frame->format = AV_PIX_FMT_MMAL; frame->data[3] = (uint8_t *)ref->buffer; return 0; }
static void ff_mediacodec_dec_unref(MediaCodecDecContext *s) { if (!s) return; if (!avpriv_atomic_int_add_and_fetch(&s->refcount, -1)) { if (s->codec) { ff_AMediaCodec_delete(s->codec); s->codec = NULL; } if (s->format) { ff_AMediaFormat_delete(s->format); s->format = NULL; } if (s->surface) { ff_mediacodec_surface_unref(s->surface, NULL); s->surface = NULL; } av_freep(&s->codec_name); av_freep(&s); } }
int main(void) { volatile int val = 1; int res; res = avpriv_atomic_int_add_and_fetch(&val, 1); assert(res == 2); avpriv_atomic_int_set(&val, 3); res = avpriv_atomic_int_get(&val); assert(res == 3); return 0; }
static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { AVCodecContext *avctx = (AVCodecContext*)port->userdata; MMALDecodeContext *ctx = avctx->priv_data; if (!buffer->cmd) { FFBufferEntry *entry = buffer->user_data; av_buffer_unref(&entry->ref); if (entry->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) avpriv_atomic_int_add_and_fetch(&ctx->packets_buffered, -1); av_free(entry); } mmal_buffer_header_release(buffer); }
// Move prepared/split packets from waiting_buffers to the MMAL decoder. static int ffmmal_fill_input_port(AVCodecContext *avctx) { MMALDecodeContext *ctx = avctx->priv_data; while (ctx->waiting_buffers) { MMAL_BUFFER_HEADER_T *mbuffer; FFBufferEntry *buffer; MMAL_STATUS_T status; mbuffer = mmal_queue_get(ctx->pool_in->queue); if (!mbuffer) return 0; buffer = ctx->waiting_buffers; mmal_buffer_header_reset(mbuffer); mbuffer->cmd = 0; mbuffer->pts = buffer->pts; mbuffer->dts = buffer->dts; mbuffer->flags = buffer->flags; mbuffer->data = buffer->data; mbuffer->length = buffer->length; mbuffer->user_data = buffer; mbuffer->alloc_size = ctx->decoder->input[0]->buffer_size; // Remove from start of the list ctx->waiting_buffers = buffer->next; if (ctx->waiting_buffers_tail == buffer) ctx->waiting_buffers_tail = NULL; if ((status = mmal_port_send_buffer(ctx->decoder->input[0], mbuffer))) { mmal_buffer_header_release(mbuffer); av_buffer_unref(&buffer->ref); if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) avpriv_atomic_int_add_and_fetch(&ctx->packets_buffered, -1); av_free(buffer); } if (status) { av_log(avctx, AV_LOG_ERROR, "MMAL error %d when sending input\n", (int)status); return AVERROR_UNKNOWN; } } return 0; }
// Split packets and add them to the waiting_buffers list. We don't queue them // immediately, because it can happen that the decoder is temporarily blocked // (due to us not reading/returning enough output buffers) and won't accept // new input. (This wouldn't be an issue if MMAL input buffers always were // complete frames - then the input buffer just would have to be big enough.) // If is_extradata is set, send it as MMAL_BUFFER_HEADER_FLAG_CONFIG. static int ffmmal_add_packet(AVCodecContext *avctx, AVPacket *avpkt, int is_extradata) { MMALDecodeContext *ctx = avctx->priv_data; AVBufferRef *buf = NULL; int size = 0; uint8_t *data = (uint8_t *)""; uint8_t *start; int ret = 0; if (avpkt->size) { if (avpkt->buf) { buf = av_buffer_ref(avpkt->buf); size = avpkt->size; data = avpkt->data; } else { buf = av_buffer_alloc(avpkt->size); if (buf) { memcpy(buf->data, avpkt->data, avpkt->size); size = buf->size; data = buf->data; } } if (!buf) { ret = AVERROR(ENOMEM); goto done; } if (!is_extradata) ctx->packets_sent++; } else { if (ctx->eos_sent) goto done; if (!ctx->packets_sent) { // Short-cut the flush logic to avoid upsetting MMAL. ctx->eos_sent = 1; ctx->eos_received = 1; goto done; } } start = data; do { FFBufferEntry *buffer = av_mallocz(sizeof(*buffer)); if (!buffer) { ret = AVERROR(ENOMEM); goto done; } buffer->data = data; buffer->length = FFMIN(size, ctx->decoder->input[0]->buffer_size); if (is_extradata) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG; if (data == start) buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_START; data += buffer->length; size -= buffer->length; buffer->pts = avpkt->pts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->pts; buffer->dts = avpkt->dts == AV_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : avpkt->dts; if (!size) { buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; avpriv_atomic_int_add_and_fetch(&ctx->packets_buffered, 1); } if (!buffer->length) { buffer->flags |= MMAL_BUFFER_HEADER_FLAG_EOS; ctx->eos_sent = 1; } if (buf) { buffer->ref = av_buffer_ref(buf); if (!buffer->ref) { av_free(buffer); ret = AVERROR(ENOMEM); goto done; } } // Insert at end of the list if (!ctx->waiting_buffers) ctx->waiting_buffers = buffer; if (ctx->waiting_buffers_tail) ctx->waiting_buffers_tail->next = buffer; ctx->waiting_buffers_tail = buffer; } while (size); done: av_buffer_unref(&buf); return ret; }
static void ff_mediacodec_dec_ref(MediaCodecDecContext *s) { avpriv_atomic_int_add_and_fetch(&s->refcount, 1); }