예제 #1
0
/*------------------------------------------------------------------------------
|    OMX_MediaProcessor::mediaDecoding
+-----------------------------------------------------------------------------*/
void OMX_MediaProcessor::mediaDecoding()
{
    LOG_VERBOSE(LOG_TAG, "Decoding thread started.");
    emit playbackStarted();

    struct timespec starttime, endtime;
    while (!m_pendingStop) {
        // If a request is pending then consider done here.
        m_mutexPending.lock();
        if (m_pendingPause) {
            m_waitPendingCommand.wakeAll();
            m_pendingPause = false;
        }
        m_mutexPending.unlock();

        // TODO: Use a semaphore instead.
        if (m_state == STATE_PAUSED) {
            OMXClock::OMXSleep(2);
            continue;
        }

#if 0 // TODO: Reimplement?
        if (m_incr != 0 && !m_bMpeg) {
            int    seek_flags   = 0;
            double seek_pos     = 0;
            double pts          = 0;

            pts = m_av_clock->GetPTS();

            seek_pos = (pts / DVD_TIME_BASE) + m_incr;
            seek_flags = m_incr < 0.0f ? AVSEEK_FLAG_BACKWARD : 0;

            seek_pos *= 1000.0f;

            m_incr = 0;

            if(m_omx_reader.SeekTime(seek_pos, seek_flags, &startpts))
                FlushStreams(startpts);

            m_player_video->Close();
            if(m_has_video && !m_player_video->Open(m_hints_video, m_av_clock, m_Deinterlace,  m_bMpeg,
                                                    m_hdmi_clock_sync, m_thread_player, m_display_aspect))
                goto do_exit;
        }
#endif

        // TODO: Better error handling.
        if (m_player_audio->Error()) {
            LOG_ERROR(LOG_TAG, "Audio player error. emergency exit!");
            break;
        }

        if (false) {
            LOG_INFORMATION(LOG_TAG, "V : %8.02f %8d %8d A : %8.02f %8.02f Cv : %8d Ca : %8d",
                   m_av_clock->OMXMediaTime(), m_player_video->GetDecoderBufferSize(),
                   m_player_video->GetDecoderFreeSpace(), m_player_audio->GetCurrentPTS() / DVD_TIME_BASE,
                   m_player_audio->GetDelay(), m_player_video->GetCached(), m_player_audio->GetCached());
        }

        if (m_omx_reader.IsEof() && !m_omx_pkt) {
            if (!m_player_audio->GetCached() && !m_player_video->GetCached())
                break;

            // Abort audio buffering, now we're on our own.
            if (m_buffer_empty)
                m_av_clock->OMXResume();

            OMXClock::OMXSleep(10);
            continue;
        }

        /* when the audio buffer runs under 0.1 seconds we buffer up */
        if (m_has_audio) {
            if (m_player_audio->GetDelay() < 0.1f && !m_buffer_empty) {
                if (!m_av_clock->OMXIsPaused()) {
                    m_av_clock->OMXPause();

                    LOG_VERBOSE(LOG_TAG, "Buffering starts.");
                    m_buffer_empty = true;
                    clock_gettime(CLOCK_REALTIME, &starttime);
                }
            }
            if (m_player_audio->GetDelay() > (AUDIO_BUFFER_SECONDS * 0.75f) && m_buffer_empty) {
                if (m_av_clock->OMXIsPaused()) {
                    m_av_clock->OMXResume();

                    LOG_VERBOSE(LOG_TAG, "Buffering ends.");
                    m_buffer_empty = false;
                }
            }

            if (m_buffer_empty) {
                clock_gettime(CLOCK_REALTIME, &endtime);
                if ((endtime.tv_sec - starttime.tv_sec) > BUFFERING_TIMEOUT_S) {
                    m_buffer_empty = false;
                    m_av_clock->OMXResume();
                    LOG_WARNING(LOG_TAG, "Buffering timed out.");
                }
            }
        }

        if (!m_omx_pkt)
            m_omx_pkt = m_omx_reader.Read();

        if (m_has_video && m_omx_pkt && m_omx_reader.IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index)) {
            if (m_player_video->AddPacket(m_omx_pkt))
                m_omx_pkt = NULL;
            else
                OMXClock::OMXSleep(10);

#if 0 // TODO: Reimplement?
            if(m_tv_show_info)
            {
                char response[80];
                vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
                          m_player_video->GetDecoderBufferSize()-m_player_video->GetDecoderFreeSpace(),
                          0 , 0, m_player_video->GetDecoderBufferSize());
                vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
                          (int)(100.0*m_player_audio->GetDelay()), 0, 0, 100*AUDIO_BUFFER_SECONDS);
            }
#endif
        }
        else if (m_has_audio && m_omx_pkt && m_omx_pkt->codec_type == AVMEDIA_TYPE_AUDIO) {
            if (m_player_audio->AddPacket(m_omx_pkt))
                m_omx_pkt = NULL;
            else
                OMXClock::OMXSleep(10);
        }
#ifdef ENABLE_SUBTITLES
        else if (m_omx_pkt && m_omx_reader.IsActive(OMXSTREAM_SUBTITLE, m_omx_pkt->stream_index)) {
            if (m_omx_pkt->size && ENABLE_SUBTITLES &&
                    (m_omx_pkt->hints.codec == CODEC_ID_TEXT ||
                     m_omx_pkt->hints.codec == CODEC_ID_SSA)) {
                if(m_player_subtitles->AddPacket(m_omx_pkt))
                    m_omx_pkt = NULL;
                else
                    OMXClock::OMXSleep(10);
            }
            else {
                m_omx_reader.FreePacket(m_omx_pkt);
                m_omx_pkt = NULL;
            }
        }
#endif
        else {
            if (m_omx_pkt) {
                m_omx_reader.FreePacket(m_omx_pkt);
                m_omx_pkt = NULL;
            }
        }
    }

    emit playbackCompleted();
    cleanup();
}
예제 #2
0
QSGNode* OMX_MediaProcessorElement::updatePaintNode(QSGNode*, UpdatePaintNodeData*)
{
    if (!m_texProvider) {
        m_texProvider = new OMX_TextureProviderQQuickItem(this);
        m_mediaProc   = new OMX_MediaProcessor(m_texProvider);
        connect(m_mediaProc, SIGNAL(playbackCompleted()), this, SIGNAL(playbackCompleted()));
        connect(m_mediaProc, SIGNAL(playbackStarted()), this, SIGNAL(playbackStarted()));

        // Open if filepath is set.
        // TODO: Handle errors.
        if (!m_source.isNull()) {
            //if (QFile(m_source).exists()) {
                if (openMedia(m_source))
                    m_mediaProc->play();
            //}
            //else {
                LOG_WARNING(LOG_TAG, "File does not exist.");
            //}
        }
    }

    return NULL;

#if 0
    QSGGeometryNode* node = 0;
    QSGGeometry* geometry = 0;

    if (!oldNode) {
        // Create the node.
        node = new QSGGeometryNode;
        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
        geometry->setDrawingMode(GL_TRIANGLE_STRIP);
        node->setGeometry(geometry);
        node->setFlag(QSGNode::OwnsGeometry);

        // TODO: Who is freeing this?
        // TODO: I cannot know the texture size here.
        QSGOpaqueTextureMaterial* material = new QSGOpaqueTextureMaterial;
        m_sgtexture = new OMX_SGTexture(m_texture, QSize(1920, 1080));
        material->setTexture(m_sgtexture);
        node->setMaterial(material);
        node->setFlag(QSGNode::OwnsMaterial);

#ifdef ENABLE_VIDEO_PROCESSOR
        QPlatformNativeInterface* nativeInterface =
                QGuiApplicationPrivate::platformIntegration()->nativeInterface();
        Q_ASSERT(nativeInterface);
        EGLDisplay eglDisplay = nativeInterface->nativeResourceForIntegration("egldisplay");
        EGLContext eglContext = nativeInterface->nativeResourceForContext(
                    "eglcontext",
                    QOpenGLContext::currentContext()
                    );
#endif

        // Provider MUST be built in this thread.
        m_provider  = new OMX_TextureProviderQQuickItem(this);
#ifdef ENABLE_VIDEO_PROCESSOR
        m_videoProc = new OMX_VideoProcessor(eglDisplay, eglContext, m_provider);
        connect(m_videoProc, SIGNAL(textureReady(uint)), this, SLOT(onTextureChanged(uint)));
        if (!m_source.isNull())
            m_videoProc->setVideoPath(m_source);
        if (m_playScheduled) {
            m_timer->start(30);
            m_videoProc->play();
        }
#elif ENABLE_MEDIA_PROCESSOR
        LOG_VERBOSE(LOG_TAG, "Starting video using media processor...");
        m_mediaProc = new OMX_MediaProcessor(m_provider);
        m_mediaProc->setFilename("/home/pi/usb/Cars2.mkv", m_texture);
        //if (m_playScheduled) {
            m_timer->start(40);
            m_mediaProc->play();
        //}
#else
        LOG_VERBOSE(LOG_TAG, "Starting video...");
        QtConcurrent::run(&startVideo, m_provider, this);
        m_timer->start(30);
#endif
    }
    else {
        node = static_cast<QSGGeometryNode*>(oldNode);
        geometry = node->geometry();
        geometry->allocate(4);

        // Update texture in the node if needed.
        QSGOpaqueTextureMaterial* material = (QSGOpaqueTextureMaterial*)node->material();
        if (m_texture != (GLuint)material->texture()->textureId()) {
            // TODO: Does setTextureId frees the prev texture?
            // TODO: I should the given the texture size.
            LOG_ERROR(LOG_TAG, "Updating texture to %u!", m_texture);
            material = new QSGOpaqueTextureMaterial;
            m_sgtexture->setTexture(m_texture, QSize(1920, 1080));
        }
    }

    // Create the vertices and map to texture.
    QRectF bounds = boundingRect();
    QSGGeometry::TexturedPoint2D* vertices = geometry->vertexDataAsTexturedPoint2D();
    vertices[0].set(bounds.x(), bounds.y() + bounds.height(), 0.0f, 0.0f);
    vertices[1].set(bounds.x() + bounds.width(), bounds.y() + bounds.height(), 1.0f, 0.0f);
    vertices[2].set(bounds.x(), bounds.y(), 0.0f, 1.0f);
    vertices[3].set(bounds.x() + bounds.width(), bounds.y(), 1.0f, 1.0f);
    return node;
#endif
}
예제 #3
0
/*------------------------------------------------------------------------------
|    OMX_MediaProcessor::mediaDecoding
+-----------------------------------------------------------------------------*/
void OMX_MediaProcessor::mediaDecoding()
{
   // See description in the qmakefile.
//#define ENABLE_PROFILE_MAIN_LOOP
//#define ENABLE_PAUSE_FOR_BUFFERING

   LOG_VERBOSE(LOG_TAG, "Decoding thread started.");
   emit playbackStarted();

   // Prealloc.
#ifdef ENABLE_PAUSE_FOR_BUFFERING
   float stamp     = 0;
   float audio_pts = 0;
   float video_pts = 0;

   float audio_fifo = 0;
   float video_fifo = 0;
   float threshold = 0;
   bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false;
   float m_threshold = 1.0f; //std::min(0.1f, audio_fifo_size * 0.1f);
#endif // ENABLE_PAUSE_FOR_BUFFERING
   bool sentStarted = false;
   double last_seek_pos = 0;

   bool sendEos = false;
   double m_last_check_time = 0.0;

   m_av_clock->OMXReset(m_has_video, m_has_audio);
   m_av_clock->OMXStateExecute();
   sentStarted = true;

   while (!m_pendingStop) {
#ifdef ENABLE_PROFILE_MAIN_LOOP
      static qint64 tot    = 0;
      static qint64 totNum = 0;
      static QElapsedTimer timer;
      static int count = 0;
      if (tot == 0) {
         timer.start();
         tot++;
      }
      else
         tot += timer.restart();
      totNum++;
      if ((count++)%30 == 0) {
         //LOG_VERBOSE(LOG_TAG, "Elapsed: %lld", timer.restart());
         LOG_VERBOSE(LOG_TAG, "Average: %f.", (double)tot/totNum);
      }
#endif

      double now = m_av_clock->GetAbsoluteClock();
      bool update = false;
      if (m_last_check_time == 0.0 || m_last_check_time + DVD_MSEC_TO_TIME(20) <= now) {
         update = true;
         m_last_check_time = now;
      }

      // If a request is pending then consider done here.
      m_mutexPending.lock();
      if (m_pendingPause) {
         m_waitPendingCommand.wakeAll();
         m_pendingPause = false;
      }
      m_mutexPending.unlock();

      // TODO: Use a semaphore instead.
      if (m_state == STATE_PAUSED) {
         OMXClock::OMXSleep(2);
         continue;
      }

      if (m_seekFlush || m_incr != 0) {
         double seek_pos = 0;
         double pts      = m_av_clock->OMXMediaTime();

         //seek_pos        = (pts / DVD_TIME_BASE) + m_incr;
         seek_pos = (pts ? pts / DVD_TIME_BASE : last_seek_pos) + m_incr;
         last_seek_pos = seek_pos;

         seek_pos        *= 1000.0;

         if(m_omx_reader->SeekTime((int)seek_pos, m_incr < 0.0f, &startpts))
         {
            unsigned t = (unsigned)(startpts*1e-6);
            auto dur = m_omx_reader->GetStreamLength() / 1000;

            log_info("Seek to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
            flushStreams(startpts);
         }

         m_player_video->Close();
         sentStarted = false;

         if (m_omx_reader->IsEof())
            break;

         if (m_has_video && !m_player_video->Open(
                *m_hints_video,
                m_av_clock,
                m_textureData,
                VS_DEINTERLACEMODE_OFF, /* deinterlace */
                OMX_ImageFilterAnaglyphNone,
                ENABLE_HDMI_CLOCK_SYNC,
                true,                   /* threaded */
                1.0,                    /* display aspect, unused */
                0,                      /* display */
                0,                      /* layer */
                m_video_queue_size, m_video_fifo_size
                )) {
            m_incr = 0;
            break;
         }

         m_incr = 0;

#ifdef ENABLE_PAUSE_FOR_BUFFERING
         m_av_clock->OMXPause();
#endif

#ifdef ENABLE_SUBTITLES
         if (m_has_subtitle)
            m_player_subtitles.Resume();
#endif

         unsigned t = (unsigned)(startpts*1e-6);
         LOG_VERBOSE(LOG_TAG, "Seeked to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
         m_packetAfterSeek = false;
         m_seekFlush       = false;
      }
      else if (m_packetAfterSeek && TRICKPLAY(m_av_clock->OMXPlaySpeed())) {
         double seek_pos     = 0;
         double pts          = 0;

         pts      = m_av_clock->OMXMediaTime();
         seek_pos = (pts/DVD_TIME_BASE);

         seek_pos *= 1000.0;

#if 1
         if (m_omx_reader->SeekTime((int)seek_pos, m_av_clock->OMXPlaySpeed() < 0, &startpts))
         {
            ; //FlushStreams(DVD_NOPTS_VALUE);
         }
#endif // 0

         CLog::Log(LOGDEBUG, "Seeked %.0f %.0f %.0f\n", DVD_MSEC_TO_TIME(seek_pos), startpts, m_av_clock->OMXMediaTime());

         //unsigned t = (unsigned)(startpts*1e-6);
         unsigned t = (unsigned)(pts*1e-6);
         printf("Seek to: %02d:%02d:%02d\n", (t/3600), (t/60)%60, t%60);
         m_packetAfterSeek = false;
      }

      // TODO: Better error handling.
      if (m_player_audio->Error()) {
         LOG_ERROR(LOG_TAG, "Audio player error. emergency exit!");
         break;
      }

      if (update) {
#ifdef ENABLE_PAUSE_FOR_BUFFERING
         /* when the video/audio fifos are low, we pause clock, when high we resume */
         stamp     = m_av_clock->OMXMediaTime();
         audio_pts = m_player_audio->GetCurrentPTS();
         video_pts = m_player_video->GetCurrentPTS();

         if (0 && m_av_clock->OMXIsPaused()) {
            double old_stamp = stamp;
            if (audio_pts != DVD_NOPTS_VALUE && (stamp == 0 || audio_pts < stamp))
               stamp = audio_pts;
            if (video_pts != DVD_NOPTS_VALUE && (stamp == 0 || video_pts < stamp))
               stamp = video_pts;
            if (old_stamp != stamp)
            {
               m_av_clock->OMXMediaTime(stamp);
               stamp = m_av_clock->OMXMediaTime();
            }
         }

         audio_fifo = audio_pts == DVD_NOPTS_VALUE ? 0.0f : audio_pts / DVD_TIME_BASE - stamp * 1e-6;
         video_fifo = video_pts == DVD_NOPTS_VALUE ? 0.0f : video_pts / DVD_TIME_BASE - stamp * 1e-6;
         threshold  = min(0.1f, (float)m_player_audio->GetCacheTotal()*0.1f);
#endif // ENABLE_PAUSE_FOR_BUFFERING

#if 0
         static int count;
         if ((count++ & 15) == 0) {
            LOG_VERBOSE(LOG_TAG, "M: %8.02f V : %8.02f %8d %8d A : %8.02f %8.02f/%8.02f Cv : %8d Ca : %8d \r", stamp,
                        audio_fifo, m_player_video->GetDecoderBufferSize(), m_player_video->GetDecoderFreeSpace(),
                        video_fifo, m_player_audio->GetDelay(), m_player_audio->GetCacheTotal(),
                        m_player_video->GetCached(), m_player_audio->GetCached());
         }
#endif

#if 0
         if(m_tv_show_info) {
            static unsigned count;
            if ((count++ & 15) == 0) {
               char response[80];
               if (m_player_video.GetDecoderBufferSize() && m_player_audio.GetCacheTotal())
                  vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
                            (int)(100.0*m_player_video.GetDecoderBufferSize()-m_player_video.GetDecoderFreeSpace())/m_player_video.GetDecoderBufferSize(),
                            (int)(100.0*video_fifo/m_player_audio.GetCacheTotal()),
                            0, 100);
               if (m_player_audio.GetCacheTotal())
                  vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
                            (int)(100.0*audio_fifo/m_player_audio.GetCacheTotal()),
                            (int)(100.0*m_player_audio.GetDelay()/m_player_audio.GetCacheTotal()),
                            0, 100);
               vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d",
                         m_player_video.GetLevel(), 0, 0, 100);
               vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d",
                         m_player_audio.GetLevel(), 0, 0, 100);
            }
         }
#endif

#ifdef ENABLE_PAUSE_FOR_BUFFERING
         if (audio_pts != DVD_NOPTS_VALUE) {
            audio_fifo_low  = m_has_audio && audio_fifo < threshold;
            audio_fifo_high = !m_has_audio || (audio_pts != DVD_NOPTS_VALUE && audio_fifo > m_threshold);
         }

         if (video_pts != DVD_NOPTS_VALUE) {
            video_fifo_low  = m_has_video && video_fifo < threshold;
            video_fifo_high = !m_has_video || (video_pts != DVD_NOPTS_VALUE && video_fifo > m_threshold);
         }

         // Enable this to enable pause for buffering.
         if (m_state != STATE_PAUSED && (m_omx_reader->IsEof() || m_omx_pkt || TRICKPLAY(m_av_clock->OMXPlaySpeed()) || (audio_fifo_high && video_fifo_high)))
         {
            if (m_av_clock->OMXIsPaused())
            {
               CLog::Log(LOGDEBUG, "Resume %.2f,%.2f (%d,%d,%d,%d) EOF:%d PKT:%p\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_omx_reader->IsEof(), m_omx_pkt);
               log_verbose("Pausing for buffering...");
               //m_av_clock->OMXStateExecute();
               m_av_clock->OMXResume();
            }
         }
         else if (m_state == STATE_PAUSED || audio_fifo_low || video_fifo_low)
         {
            if (!m_av_clock->OMXIsPaused())
            {
               if (m_state != STATE_PAUSED)
                 m_threshold = std::min(2.0f*m_threshold, 16.0f);
               CLog::Log(LOGDEBUG, "Pause %.2f,%.2f (%d,%d,%d,%d) %.2f\n", audio_fifo, video_fifo, audio_fifo_low, video_fifo_low, audio_fifo_high, video_fifo_high, m_threshold);
               log_verbose("Buffering completed. Resuming...");
               m_av_clock->OMXPause();
            }
         }
#endif
      }

      if (!sentStarted)
      {
         CLog::Log(LOGDEBUG, "COMXPlayer::HandleMessages - player started RESET");
         m_av_clock->OMXReset(m_has_video, m_has_audio);
         m_av_clock->OMXStateExecute();
         sentStarted = true;
      }

      if (!m_omx_pkt)
         m_omx_pkt = m_omx_reader->Read();

      if (m_omx_pkt)
         sendEos = false;

      if (m_omx_reader->IsEof() && !m_omx_pkt) {
         // demuxer EOF, but may have not played out data yet
         if ((m_has_video && m_player_video->GetCached()) ||
             (m_has_audio && m_player_audio->GetCached())) {
            OMXClock::OMXSleep(10);
            continue;
         }
         if (m_loop) {
            m_incr = m_loop_from - (m_av_clock->OMXMediaTime() ? m_av_clock->OMXMediaTime() / DVD_TIME_BASE : last_seek_pos);
            continue;
         }

         if (!sendEos && m_has_video)
            m_player_video->SubmitEOS();
         if (!sendEos && m_has_audio)
            m_player_audio->SubmitEOS();
         sendEos = true;
         if ((m_has_video && !m_player_video->IsEOS()) ||
             (m_has_audio && !m_player_audio->IsEOS()) ) {
            OMXClock::OMXSleep(10);
            continue;
         }

         break;
      }

      if (!m_omx_pkt)
         m_omx_pkt = m_omx_reader->Read();

      if(m_omx_pkt)
        sendEos = false;

      if(m_omx_reader->IsEof() && !m_omx_pkt) {
        // demuxer EOF, but may have not played out data yet
        if ( (m_has_video && m_player_video->GetCached()) ||
             (m_has_audio && m_player_audio->GetCached()) )
        {
          OMXClock::OMXSleep(10);
          continue;
        }
        if (!sendEos && m_has_video)
          m_player_video->SubmitEOS();
        if (!sendEos && m_has_audio)
          m_player_audio->SubmitEOS();
        sendEos = true;
        if ( (m_has_video && !m_player_video->IsEOS()) ||
             (m_has_audio && !m_player_audio->IsEOS()) )
        {
          OMXClock::OMXSleep(10);
          continue;
        }
        break;
      }

      if(m_has_video && m_omx_pkt && m_omx_reader->IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index))
      {
        if (TRICKPLAY(m_av_clock->OMXPlaySpeed()))
        {
           m_packetAfterSeek = true;
        }
        if(m_player_video->AddPacket(m_omx_pkt))
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
      else if(m_has_audio && m_omx_pkt && !TRICKPLAY(m_av_clock->OMXPlaySpeed()) && m_omx_pkt->codec_type == AVMEDIA_TYPE_AUDIO)
      {
        if(m_player_audio->AddPacket(m_omx_pkt))
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
#ifdef ENABLE_SUBTITLES
      else if(m_has_subtitle && m_omx_pkt && !TRICKPLAY(m_av_clock->OMXPlaySpeed()) &&
              m_omx_pkt->codec_type == AVMEDIA_TYPE_SUBTITLE)
      {
        auto result = m_player_subtitles.AddPacket(m_omx_pkt,
                        m_omx_reader.GetRelativeIndex(m_omx_pkt->stream_index));
        if (result)
          m_omx_pkt = NULL;
        else
          OMXClock::OMXSleep(10);
      }
#endif
      else
      {
        if(m_omx_pkt)
        {
          m_omx_reader->FreePacket(m_omx_pkt);
          m_omx_pkt = NULL;
        }
        else
          OMXClock::OMXSleep(10);
      }
   }

   LOG_VERBOSE(LOG_TAG, "Stopping OMX clock...");
   //m_av_clock->OMXResume();
   m_av_clock->OMXStop();
   m_av_clock->OMXStateIdle();
   //m_av_clock->OMXStateExecute();
   //m_av_clock->OMXReset(m_has_video, m_has_audio);

   // Restart video player. It seems it is necessary to close
   // and open again. omxplayer does this also when seeking so
   // maybe there is no other way to restart it.
   m_player_video->Close();
   if (m_has_video)
      if (!m_player_video->Open(
             *m_hints_video,
             m_av_clock,
             m_textureData,
             VS_DEINTERLACEMODE_OFF, /* deinterlace */
             OMX_ImageFilterAnaglyphNone,
             ENABLE_HDMI_CLOCK_SYNC,
             true,                   /* threaded */
             1.0,                    /* display aspect, unused */
             0,                      /* display, unused */
             0,                      /* layer */
             m_video_queue_size, m_video_fifo_size
             )) {
         LOG_ERROR(LOG_TAG, "Failed to reopen media.");
      }
   // TODO: Handle failure.

   setState(STATE_STOPPED);
   emit playbackCompleted();

   // Actually change the state here and reset flags.
   m_mutexPending.lock();
   if (m_pendingStop) {
      m_pendingStop = false;
      m_waitPendingCommand.wakeAll();
   }
   m_mutexPending.unlock();
}