Exemplo n.º 1
0
SINT SoundSourceFFmpeg::seekSampleFrame(SINT frameIndex) {
    DEBUG_ASSERT(isValidFrameIndex(frameIndex));

    int ret = 0;
    qint64 i = 0;

    if (frameIndex < 0 || frameIndex < m_lCacheStartFrame) {
        ret = avformat_seek_file(m_pFormatCtx,
                                 m_iAudioStream,
                                 0,
                                 32767 * 2,
                                 32767 * 2,
                                 AVSEEK_FLAG_BACKWARD);


        if (ret < 0) {
            qDebug() << "SoundSourceFFmpeg::seek: Can't seek to 0 byte!";
            return -1;
        }

        clearCache();
        m_lCacheStartFrame = 0;
        m_lCacheEndFrame = 0;
        m_lCacheLastPos = 0;
        m_lCacheFramePos = 0;
        m_lStoredSeekPoint = -1;


        // Try to find some jump point near to
        // where we are located so we don't needed
        // to try guess it
        if (frameIndex >= AUDIOSOURCEFFMPEG_POSDISTANCE) {
            for (i = 0; i < m_SJumpPoints.size(); i ++) {
                if (m_SJumpPoints[i]->startFrame >= frameIndex && i > 2) {
                    m_lCacheFramePos = m_SJumpPoints[i - 2]->startFrame * 2;
                    m_lStoredSeekPoint = m_SJumpPoints[i - 2]->pos;
                    break;
                }
            }
        }

        if (frameIndex == 0) {
            readFramesToCache((AUDIOSOURCEFFMPEG_CACHESIZE - 50), -1);
        } else {
            readFramesToCache((AUDIOSOURCEFFMPEG_CACHESIZE / 2), frameIndex);
        }
    }


    if (m_lCacheEndFrame <= frameIndex) {
        readFramesToCache(100, frameIndex);
    }

    m_currentMixxxFrameIndex = frameIndex;

    m_bIsSeeked = TRUE;

    return frameIndex;
}
Exemplo n.º 2
0
SINT SoundSourceFFmpeg::seekSampleFrame(SINT frameIndex) {
    DEBUG_ASSERT(isValidFrameIndex(frameIndex));

    int ret = 0;
    qint64 i = 0;
    struct ffmpegLocationObject *l_STestObj = nullptr;

    if (frameIndex < 0 || frameIndex < m_lCacheStartFrame) {
        // Seek to set (start of the stream which is FFmpeg frame 0)
        // because we are dealing with compressed audio FFmpeg takes
        // best of to seek that point (in this case 0 Is always there)
        // in every other case we should provide MIN and MAX tolerance
        // which we can take.
        // FFmpeg just just can't take zero as MAX tolerance so we try to
        // just make some tolerable (which is never used because zero point
        // should always be there) some number (which is 0xffff 65535)
        // that is chosen because in WMA frames can be that big and if it's
        // smaller than the frame we are seeking we can get into error
        ret = avformat_seek_file(m_pFormatCtx,
                                 m_iAudioStream,
                                 0,
                                 0,
                                 0xffff,
                                 AVSEEK_FLAG_BACKWARD);

        if (ret < 0) {
            qDebug() << "SoundSourceFFmpeg::seek: Can't seek to 0 byte!";
            return -1;
        }

        clearCache();
        m_lCacheStartFrame = 0;
        m_lCacheEndFrame = 0;
        m_lCacheLastPos = 0;
        m_lCacheFramePos = 0;
        m_lStoredSeekPoint = -1;


        // Try to find some jump point near to
        // where we are located so we don't needed
        // to try guess it
        if (m_SJumpPoints.size() > 0) {
            l_STestObj = m_SJumpPoints.first();

            if (frameIndex > l_STestObj->startFrame) {
                for (i = 0; i < m_SJumpPoints.size(); i++) {
                    if (m_SJumpPoints[i]->startFrame >= frameIndex) {
                        if (i > 0) {
                            i--;
                        }

                        m_lCacheFramePos = m_SJumpPoints[i]->startFrame;
                        m_lStoredSeekPoint = m_SJumpPoints[i]->pos;
                        m_SStoredJumpPoint = m_SJumpPoints[i];
                        break;
                    }
                }
            }
        }

        if (frameIndex == 0) {
            // Because we are in the beginning just read cache full
            // but leave 50 of just in case
            // -1 one means we are seeking from current position and
            // filling the cache
            readFramesToCache((AUDIOSOURCEFFMPEG_CACHESIZE - 50),
                              AUDIOSOURCEFFMPEG_FILL_FROM_CURRENTPOS);
        }
    }

    if (m_lCacheEndFrame <= frameIndex) {
        // Cache tries to read until it gets to frameIndex
        // after that we still read 100 FFmpeg frames to memory
        // so we have good cache to go forward (100) and backward (900)
        // from the point
        readFramesToCache(100, frameIndex);
    }

    m_currentMixxxFrameIndex = frameIndex;

    m_bIsSeeked = true;

    return frameIndex;
}
Exemplo n.º 3
0
bool SoundSourceFFmpeg::getBytesFromCache(CSAMPLE* buffer, SINT offset,
        SINT size) {
    struct ffmpegCacheObject *l_SObj = nullptr;
    qint32 l_lPos = 0;
    quint32 l_lLeft = AUDIOSOURCEFFMPEG_MIXXXFRAME_TO_BYTEOFFSET(size);
    quint32 l_lOffset = 0;
    quint32 l_lBytesToCopy = 0;
    bool l_bEndOfFile = false;

    char *l_pBuffer = (char *)buffer;

    // If cache is empty then retun without crash.
    if (m_SCache.isEmpty()) {
        qDebug() << "SoundSourceFFmpeg::getBytesFromCache: Cache is empty can't return bytes";
        memset(l_pBuffer, 0x00, l_lLeft);
        return false;
    }

    // Is offset bigger than start of cache
    if (offset >= m_lCacheStartFrame) {
        int l_lTmpLen = 0;
        // If last pos is (which is shouldn't) use caches end
        if (m_lCacheLastPos == 0) {
            m_lCacheLastPos = m_SCache.size() - 1;
        }

        // Seek to correct FrameIndex (Minus 5 for faster seek)
        //
        // This could be done per steps but because there
        // Jump points can be far away and codec frames are small
        // just jump to point where is safe to start.
        for (l_lPos = m_lCacheLastPos; l_lPos >= 0; l_lPos -= 5) {
            l_SObj = m_SCache[l_lPos];

            // Because length is in byte we have to convert it to Frames
            l_lTmpLen = AUDIOSOURCEFFMPEG_BYTEOFFSET_TO_MIXXXFRAME(l_SObj->length);

            if ((l_SObj->startFrame + l_lTmpLen) < offset) {
                break;
            }
        }

        // Because we step 5 backward we can end up to below zero
        // We can't go futher so hope for the best
        if (l_lPos < 0) {
            l_lPos = 0;
        }

        // This shouldn't never happen.. because it's nearly imposible
        // but because it can happen double check
        if (l_lPos >= m_SCache.size()) {
            l_lPos = m_SCache.size() - 1;
        }

        // Use this Cache object as starting point
        l_SObj = m_SCache[l_lPos];

        if (l_SObj == nullptr) {
            qDebug() << "SoundSourceFFmpeg::getBytesFromCache: Cache object nullptr";
            return false;
        }

        if (l_pBuffer == nullptr) {
            qDebug() << "SoundSourceFFmpeg::getBytesFromCache: Out buffer nullptr";
            return false;
        }

        while (l_lLeft > 0) {
            // If Cache is running low read more
            if ((l_lPos + 5) > m_SCache.size() && l_bEndOfFile == false) {
                offset = l_SObj->startFrame;
                // Read 50 frames from current pos. If we hit file end before that
                // exit
                if (readFramesToCache(50, AUDIOSOURCEFFMPEG_FILL_FROM_CURRENTPOS) == false) {
                    // File has ended.. don't try to cache anymore
                    // or some fatal error has occurred so.. just don't
                    l_bEndOfFile = true;
                }

                // Seek back to correct place
                for (l_lPos = (m_SCache.size() - 50); l_lPos > 0; l_lPos--) {
                    l_SObj = m_SCache[l_lPos];
                    if ((l_SObj->startFrame + l_SObj->length) < offset) {
                        break;
                    }
                }

                if (l_lPos < m_SCache.size() && l_lPos >= 0) {
                    l_SObj = m_SCache[l_lPos];
                    continue;
                } else if (l_lPos < 0) {
                    l_lPos = 0;
                } else {
                    l_SObj = m_SCache.last();
                    l_lPos = l_lPos < m_SCache.size() - 1;
                }
            }

            // If Cache object ain't correct then calculate offset
            if (l_SObj->startFrame <= offset) {
                // We have to convert again it to bytes
                l_lOffset = AUDIOSOURCEFFMPEG_MIXXXFRAME_TO_BYTEOFFSET(offset - l_SObj->startFrame);
            }

            // Okay somehow offset is bigger than our Cache object have bytes
            if (l_lOffset >= l_SObj->length) {
                if ((l_lPos + 1) < m_SCache.size()) {
                    l_SObj = m_SCache[++ l_lPos];
                    continue;
                } else {
                    qDebug() <<
                             "SoundSourceFFmpeg::getBytesFromCache: Buffer run out. Shouldn't happen!";
                    memset(l_pBuffer, 0x00, l_lLeft);
                    return false;
                }
            }

            // If bytes left is bigger than FFmpeg frame bytes available
            // then copy to buffer end and then jump to next FFmpeg frame
            // to understand this here are some examples
            //   * MP3 have size 2304 * 4
            //   * OGG/Opus size 256 - 1024
            //   * WMA size 32767 - 131070
            // and all these are separated in packets nor solid stream of bytes
            // that just can be copied to buffer
            // so that's why this kind of abstraction is needed
            if (l_lLeft > (l_SObj->length - l_lOffset)) {
                // calculate start point of copy
                l_lBytesToCopy = l_SObj->length - l_lOffset;
                memcpy(l_pBuffer, (l_SObj->bytes + l_lOffset), l_lBytesToCopy);
                l_lOffset = 0;
                l_pBuffer += l_lBytesToCopy;
                l_lLeft -= l_lBytesToCopy;
            } else {
                memcpy(l_pBuffer, (l_SObj->bytes + l_lOffset), l_lLeft);
                l_lLeft = 0;
            }

            // If we have more items of cache use them
            // or after that just zero buffer..
            if ((l_lPos + 1) < m_SCache.size()) {
                l_SObj = m_SCache[++ l_lPos];
            } else {
                // With MP3 VBR length of audio is just a guess
                // it's near good as it can get but it can be too long
                // so fill buffer with 0x00 (zero) that we don't get ugly
                // noise at the end of the file
                memset(l_pBuffer, 0x00, l_lLeft);
                l_lLeft = 0;
            }
        }

        m_lCacheLastPos = --l_lPos;
        return true;
    }

    return false;
}
Exemplo n.º 4
0
bool SoundSourceFFmpeg::getBytesFromCache(char *buffer, SINT offset,
        SINT size) {
    struct ffmpegCacheObject *l_SObj = NULL;
    quint32 l_lPos = 0;
    quint32 l_lLeft = 0;
    quint32 l_lOffset = 0;
    quint32 l_lBytesToCopy = 0;

    // Is offset bigger than start of cache
    if (offset >= m_lCacheStartFrame) {
        // If last pos is (which is shouldn't) use caches end
        if (m_lCacheLastPos == 0) {
            m_lCacheLastPos = m_SCache.size() - 1;
        }

        // Seek to correct FrameIndex
        for (l_lPos = m_lCacheLastPos; l_lPos > 0; l_lPos --) {
            l_SObj = m_SCache[l_lPos];
            if ((l_SObj->startFrame + l_SObj->length) < offset) {
                break;
            }
        }

        // Use this Cache object as starting point
        l_SObj = m_SCache[l_lPos];

        // Calculate in other words get bytes how much we must copy to
        // buffer (CSAMPLE = 4 and we have 2 channels which is 8 times)
        l_lLeft = (size * sizeof(CSAMPLE)) * 2;
        memset(buffer, 0x00, l_lLeft);
        while (l_lLeft > 0) {
            // If Cache is running low read more
            if (l_SObj == NULL || (l_lPos + 5) > (unsigned int)m_SCache.size()) {
                offset = l_SObj->startFrame;
                if (readFramesToCache(50, -1) == false) {
                    return false;
                }
                // Seek back to correct place
                for (l_lPos = (m_SCache.size() - 50); l_lPos > 0; l_lPos --) {
                    l_SObj = m_SCache[l_lPos];
                    if ((l_SObj->startFrame + l_SObj->length) < offset) {
                        break;
                    }
                }
                l_SObj = m_SCache[l_lPos];
                continue;
            }

            // If Cache object ain't correct then calculate offset
            if (l_SObj->startFrame <= offset) {
                // We have to convert again it to bytes
                l_lOffset = (offset - l_SObj->startFrame) * (sizeof(CSAMPLE) * 2);
            }

            // Okay somehow offset is bigger than our Cache object have bytes
            if (l_lOffset >= l_SObj->length) {
                l_SObj = m_SCache[++ l_lPos];
                continue;
            }

            if (l_lLeft > l_SObj->length) {
                // calculate start point of copy
                l_lBytesToCopy = l_SObj->length - l_lOffset;
                memcpy(buffer, (l_SObj->bytes + l_lOffset), l_lBytesToCopy);
                l_lOffset = 0;
                buffer += l_lBytesToCopy;
                l_lLeft -= l_lBytesToCopy;
            } else {
                memcpy(buffer, l_SObj->bytes, l_lLeft);
                l_lLeft = 0;
            }

            l_SObj = m_SCache[++ l_lPos];
        }

        m_lCacheLastPos = --l_lPos;
        return true;
    }

    return false;
}