0

我的应用程序中有一个视频播放器。我对avi文件和mp3音频没有问题,但是当我播放mpg或wmv时,我必须使用avcodec_decode_audio3。前几秒钟播放,然后当缓冲区重新填充时,我会静默几秒钟,然后音频从同一个地方继续,每次缓冲区重新填充时都会发生这种情况。

这是音频队列格式:

        playState.format.mSampleRate = _av->audio.sample_rate;
        playState.format.mFormatID = kAudioFormatLinearPCM;
        playState.format.mFormatFlags =  kAudioFormatFlagsCanonical;
        playState.format.mChannelsPerFrame = _av->audio.channels_per_frame;
        playState.format.mBytesPerPacket = sizeof(AudioSampleType) *_av->audio.channels_per_frame;
        playState.format.mBytesPerFrame = sizeof(AudioSampleType) *_av->audio.channels_per_frame;
        playState.format.mBitsPerChannel = 8 * sizeof(AudioSampleType);

        playState.format.mFramesPerPacket = 1;
        playState.format.mReserved = 0;

填充音频缓冲区:

static void fillAudioBuffer(AudioQueueRef queue, AudioQueueBufferRef buffer){

int lengthCopied = INT32_MAX;
int dts= 0;
int isDone = 0;

buffer->mAudioDataByteSize = 0;
buffer->mPacketDescriptionCount = 0;

OSStatus err = 0;
AudioTimeStamp bufferStartTime;

AudioQueueGetCurrentTime(queue, NULL, &bufferStartTime, NULL);

while(buffer->mPacketDescriptionCount < numPacketsToRead && lengthCopied > 0){

    lengthCopied = getNextAudio(_av,buffer->mAudioDataBytesCapacity-buffer->mAudioDataByteSize, (uint8_t*)buffer->mAudioData+buffer->mAudioDataByteSize,&dts,&isDone);
    if(!lengthCopied || isDone) break;

    if(aqStartDts < 0) aqStartDts = dts;
    if(buffer->mPacketDescriptionCount ==0){
        bufferStartTime.mFlags = kAudioTimeStampSampleTimeValid;
        bufferStartTime.mSampleTime = (Float64)(dts-aqStartDts);
    }
    buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mStartOffset = buffer->mAudioDataByteSize;
    buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mDataByteSize = lengthCopied;
    buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mVariableFramesInPacket = _av->audio.frame_size;
    buffer->mPacketDescriptionCount++;
    buffer->mAudioDataByteSize += lengthCopied;

}
if(buffer->mAudioDataByteSize){
    if((err=AudioQueueEnqueueBufferWithParameters(queue, buffer, 0, NULL, 0, 0, 0, NULL, &bufferStartTime, NULL)))
    {

    }
}


int   getNextAudio(video_data_t* vInst, int maxlength, uint8_t* buf, int* pts, int* isDone) {
struct video_context_t  *ctx = vInst->context;
int    datalength            = 0;
while(ctx->audio_ring.lock || ((ctx->audio_ring.count <= 0 && ((ctx->play_state & STATE_DIE) != STATE_DIE))&&((ctx->play_state & STATE_EOF) != STATE_EOF))){
    PMSG1(stdout,"die get audio %d", ctx->play_state);
    if((ctx->play_state & STATE_STOP) != STATE_STOP){
        PMSG1(stdout,"die NO CARGADO %d",ctx->play_state);
        return 0;
    }
    usleep(100);
}
*pts = 0;
ctx->audio_ring.lock = kLocked;

if(ctx->audio_ring.count>0 && maxlength > ctx->audio_buffer[ctx->audio_ring.read].size){
    memcpy(buf, ctx->audio_buffer[ctx->audio_ring.read].data, ctx->audio_buffer[ctx->audio_ring.read].size);
    datalength = ctx->audio_buffer[ctx->audio_ring.read].size;
    *pts = ctx->audio_buffer[ctx->audio_ring.read].pts;
    ctx->audio_ring.read++;
    ctx->audio_ring.read %= ABUF_SIZE;
    ctx->audio_ring.count--;
}
ctx->audio_ring.lock = kUnlocked;

if((ctx->play_state & STATE_EOF) == STATE_EOF && ctx->audio_ring.count == 0) *isDone = 1;
return datalength;

这是播放 mpg 文件的日志:

Input #0, mpeg, '1.MPG':
  Duration: 00:03:14.74, start: 3370.475789, bitrate: 2489 kb/s
    Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p, 544x576 [SAR 24:17 DAR 4:3], 9000 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc
    Stream #0:1[0x1c0]: Audio: mp2, 48000 Hz, stereo, s16, 192 kb/s
mpeg2video  MPEG-2 video 
aspect 1.333333
startPlayback
DTS: 0.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 303347520
Video Buffer: 157/1024 Audio Buffer: 33/1024
Bytes copied for buffer 0xc292ac0: 1046016
DTS: 490320.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 303837840
Video Buffer: 276/1024 Audio Buffer: 2/1024
Bytes copied for buffer 0x1225f8b0: 1046016
DTS: 980640.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 304328160
Video Buffer: 411/1024 Audio Buffer: 1/1024
Bytes copied for buffer 0x13380840: 1046016
DTS: 1470960.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 304818480
Video Buffer: 885/1024 Audio Buffer: 797/1024
Bytes copied for buffer 0xc292ac0: 1046016
-----Here the audio stop for 4 or 5 seconds
-----then continues for 4 or 5 seconds 
DTS: 1961280.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 305308800
Video Buffer: 765/1024 Audio Buffer: 797/1024
Bytes copied for buffer 0x1225f8b0: 1046016
-----Here the audio stop for 4 or 5 seconds
-----then continues for 4 or 5 seconds 
DTS: 2451600.000000 time base: 0.000011 StartDTS: 303347520 Orig DTS: 305799120
Video Buffer: 644/1024 Audio Buffer: 798/1024
Bytes copied for buffer 0x13380840: 1046016
...

如果我减少缓冲区,则静音和声音时间会减少。所以我想知道如何解决它?谢谢!!

4

1 回答 1

0

我有一个类似的问题,虽然不完全相同。我什至不确定 iOS 是否会查看 mSampleTime(需要对此进行试验),但我突然想到的一件事是 mSampleTime 不是以时间为单位,而是以样本为单位。代替

if(buffer->mPacketDescriptionCount ==0){
    bufferStartTime.mFlags = kAudioTimeStampSampleTimeValid;
    bufferStartTime.mSampleTime = (Float64)(dts-aqStartDts);
}

要设置 bufferStartTime,我使用以下内容:

AudioTimeStamp presentationTime = { 0 };
AudioTimeStamp actualStartTime = { 0 };

presentationTime.mFlags = kAudioTimeStampSampleTimeValid;
presentationTime.mSampleTime = (Float64) (block->presentationTime / (Float64) 1000000000.0) * (Float64) format.mSampleRate;

AudioQueueEnqueueBufferWithParameters(output, buffer, 0, NULL, trimFramesStart, trimFramesEnd, 0, NULL, &presentationTime, &actualStartTime);

当然,上面的代码片段引用了我没有在这里定义的数据结构(我没有定义我的块对象,并且 presentationTime 以纳秒为单位)。同样,当我通过 AudioQueueGetCurrentTime 从音频队列中读取时间时,我自己似乎有时间漂移(将视频同步到音频中的有效位置,似乎有一个微小的恒定偏移量,对我来说随着时间的推移复合 A/V 去同步化)。还没有玩过其他音频格式。

于 2013-08-21T20:02:59.770 回答