Example #1
0
bool CMMALVideo::SendCodecConfigData()
{
  MMAL_STATUS_T status;
  if (!m_dec_input_pool)
    return true;
  // send code config data
  MMAL_BUFFER_HEADER_T *buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500);
  if (!buffer)
  {
    CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__);
    return false;
  }

  mmal_buffer_header_reset(buffer);
  buffer->cmd = 0;
  buffer->length = std::min(m_hints.extrasize, buffer->alloc_size);
  memcpy(buffer->data, m_hints.extradata, buffer->length);
  buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_CONFIG;
  if (g_advancedSettings.CanLogComponent(LOGVIDEO))
    CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d flags:%x", CLASSNAME, __func__, buffer, buffer->length, buffer->flags);
  status = mmal_port_send_buffer(m_dec_input, buffer);
  if (status != MMAL_SUCCESS)
  {
    CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
    return false;
  }
  return true;
}
Example #2
0
int CMMALRenderer::GetImage(YV12Image *image, int source, bool readonly)
{
#if defined(MMAL_DEBUG_VERBOSE)
    CLog::Log(LOGDEBUG, "%s::%s - %p %d %d", CLASSNAME, __func__, image, source, readonly);
#endif
    if (!image) return -1;

    if( source < 0)
        return -1;

    if (m_format == RENDER_FMT_MMAL)
    {
    }
    else if (m_format == RENDER_FMT_YUV420P)
    {
        const int pitch = ALIGN_UP(m_sourceWidth, 32);
        const int aligned_height = ALIGN_UP(m_sourceHeight, 16);

        MMAL_BUFFER_HEADER_T *buffer = mmal_queue_timedwait(m_vout_input_pool->queue, 500);
        if (!buffer)
        {
            CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__);
            return -1;
        }

        mmal_buffer_header_reset(buffer);

        buffer->length = 3 * pitch * aligned_height >> 1;
        assert(buffer->length <= buffer->alloc_size);

        image->width    = m_sourceWidth;
        image->height   = m_sourceHeight;
        image->flags    = 0;
        image->cshift_x = 1;
        image->cshift_y = 1;
        image->bpp      = 1;

        image->stride[0] = pitch;
        image->stride[1] = image->stride[2] = pitch>>image->cshift_x;

        image->planesize[0] = pitch * aligned_height;
        image->planesize[1] = image->planesize[2] = (pitch>>image->cshift_x)*(aligned_height>>image->cshift_y);

        image->plane[0] = (uint8_t *)buffer->data;
        image->plane[1] = image->plane[0] + image->planesize[0];
        image->plane[2] = image->plane[1] + image->planesize[1];

        CLog::Log(LOGDEBUG, "%s::%s - %p %d", CLASSNAME, __func__, buffer, source);
        YUVBUFFER &buf = m_buffers[source];
        memset(&buf, 0, sizeof buf);
        buf.mmal_buffer = buffer;
    }
    else assert(0);
Example #3
0
CMMALRenderer::CMMALRenderer()
    : CThread("CMMALRenderer")
{
    CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
    m_vout = NULL;
    m_vout_input = NULL;
    m_vout_input_pool = NULL;
    memset(m_buffers, 0, sizeof m_buffers);
    mmal_buffer_header_reset(&m_quit_packet);
    m_release_queue = mmal_queue_create();
    m_iYV12RenderBuffer = 0;
    Create();
}
Example #4
0
// 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;
}
Example #5
0
void CMMALVideo::Recycle(MMAL_BUFFER_HEADER_T *buffer)
{
  if (g_advancedSettings.CanLogComponent(LOGVIDEO))
    CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, buffer);

  MMAL_STATUS_T status;
  mmal_buffer_header_reset(buffer);
  buffer->cmd = 0;
  if (g_advancedSettings.CanLogComponent(LOGVIDEO))
    CLog::Log(LOGDEBUG, "%s::%s Send buffer %p from pool to decoder output port %p dts_queue(%d) ready_queue(%d) busy_queue(%d)", CLASSNAME, __func__, buffer, m_dec_output,
      m_dts_queue.size(), m_output_ready.size(), m_output_busy);
  status = mmal_port_send_buffer(m_dec_output, buffer);
  if (status != MMAL_SUCCESS)
  {
    CLog::Log(LOGERROR, "%s::%s - Failed send buffer to decoder output port (status=0%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
    return;
  }
}
Example #6
0
File: codec.c Project: Adatan/vlc
static picture_t *decode(decoder_t *dec, block_t **pblock)
{
    decoder_sys_t *sys = dec->p_sys;
    block_t *block;
    MMAL_BUFFER_HEADER_T *buffer;
    bool need_flush = false;
    uint32_t len;
    uint32_t flags = 0;
    MMAL_STATUS_T status;
    picture_t *ret = NULL;

    /*
     * Configure output port if necessary
     */
    if (sys->output_format) {
        if (change_output_format(dec) < 0)
            msg_Err(dec, "Failed to change output port format");
    }

    if (!pblock)
        goto out;

    block = *pblock;

    /*
     * Check whether full flush is required
     */
    if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) {
        flush_decoder(dec);
        block_Release(*pblock);
        return NULL;
    }

    /*
     * Send output buffers
     */
    if (atomic_load(&sys->started)) {
        buffer = mmal_queue_get(sys->decoded_pictures);
        if (buffer) {
            ret = (picture_t *)buffer->user_data;
            ret->date = buffer->pts;
            ret->b_progressive = sys->b_progressive;
            ret->b_top_field_first = sys->b_top_field_first;

            if (sys->output_pool) {
                buffer->data = NULL;
                mmal_buffer_header_reset(buffer);
                mmal_buffer_header_release(buffer);
            }
        }

        fill_output_port(dec);
    }

    if (ret)
        goto out;

    /*
     * Process input
     */
    if (!block)
        goto out;

    *pblock = NULL;

    if (block->i_flags & BLOCK_FLAG_CORRUPTED)
        flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;

    vlc_mutex_lock(&sys->mutex);
    while (block->i_buffer > 0) {
        buffer = mmal_queue_timedwait(sys->input_pool->queue, 2);
        if (!buffer) {
            msg_Err(dec, "Failed to retrieve buffer header for input data");
            need_flush = true;
            break;
        }
        mmal_buffer_header_reset(buffer);
        buffer->cmd = 0;
        buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts;
        buffer->dts = block->i_dts;
        buffer->alloc_size = sys->input->buffer_size;

        len = block->i_buffer;
        if (len > buffer->alloc_size)
            len = buffer->alloc_size;

        buffer->data = block->p_buffer;
        block->p_buffer += len;
        block->i_buffer -= len;
        buffer->length = len;
        if (block->i_buffer == 0)
            buffer->user_data = block;
        buffer->flags = flags;

        status = mmal_port_send_buffer(sys->input, buffer);
        if (status != MMAL_SUCCESS) {
            msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)",
                    status, mmal_status_to_string(status));
            break;
        }
        atomic_fetch_add(&sys->input_in_transit, 1);
    }
    vlc_mutex_unlock(&sys->mutex);

out:
    if (need_flush)
        flush_decoder(dec);

    return ret;
}
Example #7
0
File: codec.c Project: Adatan/vlc
static int send_output_buffer(decoder_t *dec)
{
    decoder_sys_t *sys = dec->p_sys;
    MMAL_BUFFER_HEADER_T *buffer;
    picture_sys_t *p_sys;
    picture_t *picture;
    MMAL_STATUS_T status;
    unsigned buffer_size = 0;
    int ret = 0;

    if (!sys->output->is_enabled)
        return VLC_EGENERIC;

    /* If local output pool is allocated, use it - this is only the case for
     * non-opaque modes */
    if (sys->output_pool) {
        buffer = mmal_queue_get(sys->output_pool->queue);
        if (!buffer) {
            msg_Warn(dec, "Failed to get new buffer");
            return VLC_EGENERIC;
        }
    }

    picture = decoder_NewPicture(dec);
    if (!picture) {
        msg_Warn(dec, "Failed to get new picture");
        ret = -1;
        goto err;
    }

    p_sys = picture->p_sys;
    for (int i = 0; i < picture->i_planes; i++)
        buffer_size += picture->p[i].i_lines * picture->p[i].i_pitch;

    if (sys->output_pool) {
        mmal_buffer_header_reset(buffer);
        buffer->user_data = picture;
        buffer->alloc_size = sys->output->buffer_size;
        if (buffer_size < sys->output->buffer_size) {
            msg_Err(dec, "Retrieved picture with too small data block (%d < %d)",
                    buffer_size, sys->output->buffer_size);
            ret = VLC_EGENERIC;
            goto err;
        }

        if (!sys->opaque)
            buffer->data = picture->p[0].p_pixels;
    } else {
        buffer = p_sys->buffer;
        if (!buffer) {
            msg_Warn(dec, "Picture has no buffer attached");
            picture_Release(picture);
            return VLC_EGENERIC;
        }
        buffer->data = p_sys->buffer->data;
    }
    buffer->cmd = 0;

    status = mmal_port_send_buffer(sys->output, buffer);
    if (status != MMAL_SUCCESS) {
        msg_Err(dec, "Failed to send buffer to output port (status=%"PRIx32" %s)",
                status, mmal_status_to_string(status));
        ret = -1;
        goto err;
    }
    atomic_fetch_add(&sys->output_in_transit, 1);

    return ret;

err:
    if (picture)
        picture_Release(picture);
    if (sys->output_pool && buffer) {
        buffer->data = NULL;
        mmal_buffer_header_release(buffer);
    }
    return ret;
}
Example #8
0
int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
{
  //if (g_advancedSettings.CanLogComponent(LOGVIDEO))
  //  CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f dts_queue(%d) ready_queue(%d) busy_queue(%d)",
  //    CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_dts_queue.size(), m_output_ready.size(), m_output_busy);

  unsigned int demuxer_bytes = 0;
  uint8_t *demuxer_content = NULL;
  MMAL_BUFFER_HEADER_T *buffer;
  MMAL_STATUS_T status;

  while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer)
    Recycle(buffer);
  // we need to queue then de-queue the demux packet, seems silly but
  // mmal might not have an input buffer available when we are called
  // and we must store the demuxer packet and try again later.
  // try to send any/all demux packets to mmal decoder.
  unsigned space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size;
  if (pData && m_demux_queue.empty() && space >= (unsigned int)iSize)
  {
    demuxer_bytes = iSize;
    demuxer_content = pData;
  }
  else if (pData && iSize)
  {
    mmal_demux_packet demux_packet;
    demux_packet.dts = dts;
    demux_packet.pts = pts;
    demux_packet.size = iSize;
    demux_packet.buff = new uint8_t[iSize];
    memcpy(demux_packet.buff, pData, iSize);
    m_demux_queue_length += demux_packet.size;
    m_demux_queue.push(demux_packet);
  }

  uint8_t *buffer_to_free = NULL;

  while (1)
  {
     while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer)
       Recycle(buffer);

     space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size;
     if (!demuxer_bytes && !m_demux_queue.empty())
     {
       mmal_demux_packet &demux_packet = m_demux_queue.front();
       if (space >= (unsigned int)demux_packet.size)
       {
         // need to lock here to retrieve an input buffer and pop the queue
         m_demux_queue_length -= demux_packet.size;
         m_demux_queue.pop();
         demuxer_bytes = (unsigned int)demux_packet.size;
         demuxer_content = demux_packet.buff;
         buffer_to_free = demux_packet.buff;
         dts = demux_packet.dts;
         pts = demux_packet.pts;
       }
     }
     if (demuxer_content)
     {
       // 500ms timeout
       buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500);
       if (!buffer)
       {
         CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__);
         return VC_ERROR;
       }

       mmal_buffer_header_reset(buffer);
       buffer->cmd = 0;
       if (m_startframe && pts == DVD_NOPTS_VALUE)
         pts = 0;
       buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts;
       buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts;
       buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes;
       buffer->user_data = (void *)m_decode_frame_number;
       // set a flag so we can identify primary frames from generated frames (deinterlace)
       buffer->flags = MMAL_BUFFER_HEADER_FLAG_USER0;

       // Request decode only (maintain ref frames, but don't return a picture)
       if (m_drop_state)
         buffer->flags |= MMAL_BUFFER_HEADER_FLAG_DECODEONLY;

       memcpy(buffer->data, demuxer_content, buffer->length);
       demuxer_bytes   -= buffer->length;
       demuxer_content += buffer->length;

       if (demuxer_bytes == 0)
         buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;

       if (g_advancedSettings.CanLogComponent(LOGVIDEO))
         CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)",
            CLASSNAME, __func__, buffer, buffer->length, demuxer_bytes, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
       assert((int)buffer->length > 0);
       status = mmal_port_send_buffer(m_dec_input, buffer);
       if (status != MMAL_SUCCESS)
       {
         CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status));
         return VC_ERROR;
       }

       if (demuxer_bytes == 0)
       {
         m_decode_frame_number++;
         m_startframe = true;
         if (m_drop_state)
         {
           m_droppedPics += m_deint ? 2:1;
         }
         else
         {
           // only push if we are successful with feeding mmal
           pthread_mutex_lock(&m_output_mutex);
           m_dts_queue.push(dts);
           assert(m_dts_queue.size() < 5000);
           pthread_mutex_unlock(&m_output_mutex);
         }
         if (m_changed_count_dec != m_changed_count)
         {
           if (g_advancedSettings.CanLogComponent(LOGVIDEO))
             CLog::Log(LOGDEBUG, "%s::%s format changed frame:%d(%d)", CLASSNAME, __func__, m_changed_count_dec, m_changed_count);
           m_changed_count_dec = m_changed_count;
           if (!change_dec_output_format())
           {
             CLog::Log(LOGERROR, "%s::%s - change_dec_output_format() failed", CLASSNAME, __func__);
             return VC_ERROR;
           }
         }
         EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
         EINTERLACEMETHOD interlace_method = g_renderManager.AutoInterlaceMethod(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);

         bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive;

         if (deinterlace_request == VS_DEINTERLACEMODE_OFF)
           deinterlace = false;
         else if (deinterlace_request == VS_DEINTERLACEMODE_FORCE)
           deinterlace = true;

         if (((deinterlace && interlace_method != m_interlace_method) || !deinterlace) && m_deint)
           DestroyDeinterlace();
         if (deinterlace && !m_deint)
           CreateDeinterlace(interlace_method);

         if (buffer_to_free)
         {
           delete [] buffer_to_free;
           buffer_to_free = NULL;
           demuxer_content = NULL;
           continue;
         }
         while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer)
           Recycle(buffer);
       }
    }
    if (!demuxer_bytes)
      break;
  }
  int ret = 0;
  if (!m_output_ready.empty())
  {
    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
      CLog::Log(LOGDEBUG, "%s::%s - got space for output: demux_queue(%d) space(%d)", CLASSNAME, __func__, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
    ret |= VC_PICTURE;
  }
  if (mmal_queue_length(m_dec_input_pool->queue) > 0 && !m_demux_queue_length)
  {
    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
      CLog::Log(LOGDEBUG, "%s::%s -  got output picture:%d", CLASSNAME, __func__, m_output_ready.size());
    ret |= VC_BUFFER;
  }
  if (!ret)
  {
    if (g_advancedSettings.CanLogComponent(LOGVIDEO))
      CLog::Log(LOGDEBUG, "%s::%s - Nothing to do: dts_queue(%d) ready_queue(%d) busy_queue(%d) demux_queue(%d) space(%d)",
        CLASSNAME, __func__, m_dts_queue.size(), m_output_ready.size(), m_output_busy, m_demux_queue_length, mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size);
    Sleep(10); // otherwise we busy spin
  }
  return ret;
}