目前已实做到藉由ffmpeg接收RTSP流媒体并播放(3gp格式 AAC编码)。问题在于解码后播出的声音充满杂音,有些段落甚至被扭曲。但在先前用本地端AAC档案测试时,杂讯的程度并不是太严重。因为是第一次作流媒体客户端,说实在看不出整体设置的确切问题在哪边,还请有相关经验的前辈们帮忙看看,感谢!约略流程
-- 开启流媒体,取得格式,开启读帧与解码线程
-- 读取音频流frame
-- 解码,得到raw audio
-- 写入暂存queue ( AVPacket audio_buffer[ABUF_SIZE]; // ABUF_SIZE)
-- 播放开始:开启AudioQueue,设置音频格式,AudioBuffer
-- 从暂存queue抓取raw audio写入AudioBuffer-- 读帧与解码 -- void *parseThread(void *data){
long len;
struct ring * r;
int limit;
video_data_t * v = (video_data_t*)data;
struct video_context_t *c = v->context;
AVPacket* pkt;
printf("\n\rvideo_inst.c::parseThread: Parse Thread Started.\n");
int16_t *pDecodeBuf=(int16_t*) av_malloc(DECODEBUF_SIZE);
int decodedsize = DECODEBUF_SIZE;
UInt16 inNumofBytes = 0;
OSStatus audioErr; // Parse loop
while(likely(!(c->play_state & STATE_DIE)))
{
if(unlikely(c->seek_req > 0)){
// Received a request to seek
drainBuffers(v); // 重设buffer
av_seek_frame(c->p_format_ctx, -1, c->seek_req * AV_TIME_BASE, 0); // Seek to the appropriate time
c->seek_req = 0;
c->play_state ^= (c->play_state & STATE_EOF); // If we've reached EOF, we aren't there any longer.
continue;
}
if(unlikely((c->play_state & STATE_EOF) == STATE_EOF)){
//printf("\n\r ---- EOF ---- \n\r");
usleep(5000); // If we've reached EOF just continue to loop until the movie is closed or a seek is requested
continue;
}
len = av_read_frame(c->p_format_ctx, &c->packet); // Grab the next packet
if ( unlikely(len < 0) ) {
// If a negative number is returned, we've hit the EOF. Set the state and continue looping.
c->play_state |= STATE_EOF;
printf("\n\rvideo_inst.c::parseThread: Parse thread reached EOF.\n\r");
continue;
}
if ( c->packet.stream_index == c->idx_audio_stream && v->audio.has_audio) {
// Got an audio packet
int err;
decodedsize = DECODEBUF_SIZE;
err = avcodec_decode_audio3(c->p_audio_ctx,pDecodeBuf, &decodedsize, &c->packet);
while( (c->audio_ring.lock || c->audio_ring.count >= ABUF_SIZE) && !(c->play_state & STATE_DIE) && c->seek_req == 0) {
usleep(100);
}
if(unlikely(c->seek_req > 0)) goto skip;
if(unlikely((c->play_state & STATE_DIE) == STATE_DIE)) goto parse_thread_die;
r = &c->audio_ring;
pkt = &c->audio_buffer[r->write];
limit = ABUF_SIZE;
}
else goto skip; // Got an unsupported packet; skip this packet and free it.
if (decodedsize <= 0) goto skip;
r->lock = kLocked;
if(likely(pkt->data)){
free(pkt->data);
pkt->size=0;
pkt->data=0L;
}
// Deep copy the packet into the buffer since the packet becomes invalidated next time
// av_read_frame is called.
pkt->data = (uint8_t*)calloc(1,decodedsize);
pkt->size = decodedsize;
pkt->stream_index = c->packet.stream_index;
pkt->flags = c->packet.flags;
pkt->duration = c->packet.duration;
pkt->pos = c->packet.pos;
pkt->convergence_duration = c->packet.convergence_duration;
pkt->pts = c->packet.pts;
pkt->dts = c->packet.dts;
pkt->destruct = c->packet.destruct;
pkt->priv = &c->audio_buffer[c->audio_ring.write];
memcpy(pkt->data, pDecodeBuf, decodedsize);
r->write++;
r->count++;
if(unlikely(r->write >= limit)) r->write %= limit;
r->lock = kUnlocked;
skip:
av_free_packet(&c->packet); // Free the packet.
}
pthread_exit(NULL);
parse_thread_die:
printf("\n\rvideo_inst.c::parseThread: parse_thread_die reached.\n\r");
av_free(pDecodeBuf);
av_free_packet(&c->packet);
pthread_exit(NULL);
}-- 设置Audio Queue --- (void) startPlayback
{
OSStatus err = 0;
if(playState.playing) return; playState.started = false; if(!playState.queue)
{ UInt32 bufferSize; 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;
pauseStart = 0;
DeriveBufferSize(playState.format,playState.format.mBytesPerPacket,BUFFER_DURATION,&bufferSize,&numPacketsToRead);
err= AudioQueueNewOutput(&playState.format, aqCallback, &playState, NULL, kCFRunLoopCommonModes, 0, &playState.queue); if(err != 0)
{
printf("AQHandler.m startPlayback: Error creating new AudioQueue: %d \n", (int)err);
} for(int i = 0 ; i < NUM_BUFFERS ; i ++)
{
err = AudioQueueAllocateBufferWithPacketDescriptions(playState.queue, bufferSize, numPacketsToRead , &playState.buffers[i]); if(err != 0)
printf("AQHandler.m startPlayback: Error allocating buffer %d", i);
fillAudioBuffer(&playState,playState.queue, playState.buffers[i]);
} } startTime = mu_currentTimeInMicros(); err=AudioQueueStart(playState.queue, NULL); if(err)
{ char sErr[4];
printf("AQHandler.m startPlayback: Could not start queue %ld %s.", err, FormatError(sErr,err)); playState.playing = NO;
}
else
{
AudioSessionSetActive(true);
playState.playing = YES;
}
}
-- 开启流媒体,取得格式,开启读帧与解码线程
-- 读取音频流frame
-- 解码,得到raw audio
-- 写入暂存queue ( AVPacket audio_buffer[ABUF_SIZE]; // ABUF_SIZE)
-- 播放开始:开启AudioQueue,设置音频格式,AudioBuffer
-- 从暂存queue抓取raw audio写入AudioBuffer-- 读帧与解码 -- void *parseThread(void *data){
long len;
struct ring * r;
int limit;
video_data_t * v = (video_data_t*)data;
struct video_context_t *c = v->context;
AVPacket* pkt;
printf("\n\rvideo_inst.c::parseThread: Parse Thread Started.\n");
int16_t *pDecodeBuf=(int16_t*) av_malloc(DECODEBUF_SIZE);
int decodedsize = DECODEBUF_SIZE;
UInt16 inNumofBytes = 0;
OSStatus audioErr; // Parse loop
while(likely(!(c->play_state & STATE_DIE)))
{
if(unlikely(c->seek_req > 0)){
// Received a request to seek
drainBuffers(v); // 重设buffer
av_seek_frame(c->p_format_ctx, -1, c->seek_req * AV_TIME_BASE, 0); // Seek to the appropriate time
c->seek_req = 0;
c->play_state ^= (c->play_state & STATE_EOF); // If we've reached EOF, we aren't there any longer.
continue;
}
if(unlikely((c->play_state & STATE_EOF) == STATE_EOF)){
//printf("\n\r ---- EOF ---- \n\r");
usleep(5000); // If we've reached EOF just continue to loop until the movie is closed or a seek is requested
continue;
}
len = av_read_frame(c->p_format_ctx, &c->packet); // Grab the next packet
if ( unlikely(len < 0) ) {
// If a negative number is returned, we've hit the EOF. Set the state and continue looping.
c->play_state |= STATE_EOF;
printf("\n\rvideo_inst.c::parseThread: Parse thread reached EOF.\n\r");
continue;
}
if ( c->packet.stream_index == c->idx_audio_stream && v->audio.has_audio) {
// Got an audio packet
int err;
decodedsize = DECODEBUF_SIZE;
err = avcodec_decode_audio3(c->p_audio_ctx,pDecodeBuf, &decodedsize, &c->packet);
while( (c->audio_ring.lock || c->audio_ring.count >= ABUF_SIZE) && !(c->play_state & STATE_DIE) && c->seek_req == 0) {
usleep(100);
}
if(unlikely(c->seek_req > 0)) goto skip;
if(unlikely((c->play_state & STATE_DIE) == STATE_DIE)) goto parse_thread_die;
r = &c->audio_ring;
pkt = &c->audio_buffer[r->write];
limit = ABUF_SIZE;
}
else goto skip; // Got an unsupported packet; skip this packet and free it.
if (decodedsize <= 0) goto skip;
r->lock = kLocked;
if(likely(pkt->data)){
free(pkt->data);
pkt->size=0;
pkt->data=0L;
}
// Deep copy the packet into the buffer since the packet becomes invalidated next time
// av_read_frame is called.
pkt->data = (uint8_t*)calloc(1,decodedsize);
pkt->size = decodedsize;
pkt->stream_index = c->packet.stream_index;
pkt->flags = c->packet.flags;
pkt->duration = c->packet.duration;
pkt->pos = c->packet.pos;
pkt->convergence_duration = c->packet.convergence_duration;
pkt->pts = c->packet.pts;
pkt->dts = c->packet.dts;
pkt->destruct = c->packet.destruct;
pkt->priv = &c->audio_buffer[c->audio_ring.write];
memcpy(pkt->data, pDecodeBuf, decodedsize);
r->write++;
r->count++;
if(unlikely(r->write >= limit)) r->write %= limit;
r->lock = kUnlocked;
skip:
av_free_packet(&c->packet); // Free the packet.
}
pthread_exit(NULL);
parse_thread_die:
printf("\n\rvideo_inst.c::parseThread: parse_thread_die reached.\n\r");
av_free(pDecodeBuf);
av_free_packet(&c->packet);
pthread_exit(NULL);
}-- 设置Audio Queue --- (void) startPlayback
{
OSStatus err = 0;
if(playState.playing) return; playState.started = false; if(!playState.queue)
{ UInt32 bufferSize; 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;
pauseStart = 0;
DeriveBufferSize(playState.format,playState.format.mBytesPerPacket,BUFFER_DURATION,&bufferSize,&numPacketsToRead);
err= AudioQueueNewOutput(&playState.format, aqCallback, &playState, NULL, kCFRunLoopCommonModes, 0, &playState.queue); if(err != 0)
{
printf("AQHandler.m startPlayback: Error creating new AudioQueue: %d \n", (int)err);
} for(int i = 0 ; i < NUM_BUFFERS ; i ++)
{
err = AudioQueueAllocateBufferWithPacketDescriptions(playState.queue, bufferSize, numPacketsToRead , &playState.buffers[i]); if(err != 0)
printf("AQHandler.m startPlayback: Error allocating buffer %d", i);
fillAudioBuffer(&playState,playState.queue, playState.buffers[i]);
} } startTime = mu_currentTimeInMicros(); err=AudioQueueStart(playState.queue, NULL); if(err)
{ char sErr[4];
printf("AQHandler.m startPlayback: Could not start queue %ld %s.", err, FormatError(sErr,err)); playState.playing = NO;
}
else
{
AudioSessionSetActive(true);
playState.playing = YES;
}
}
解决方案 »
- iphone多触点应用手指如何追踪?
- beginning ios5 development 中文版
- 关于XCODE安装的疑问,不知道SNOW LEOPARD 10.6能不能装,各位看过来一下。
- MediaLibrary.mom
- iphone 程序终止时 内存如何释放
- 请教如何将unsigned short数组转换成NSString??
- 为什么NSLog和UTF8string无法输出中文
- 请教大神 ---- ios内购失败,订单核对问题
- 字符的转换问题,请前辈指导下!小弟在线等待!
- 请问这是个什么事件,在第2个tab页对应的UIViewController中写?
- 关于ios下webview的技术咨询!
- 急啊!!!关于虚拟机上安装mac os的问题!(小女感激!)
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))){
if (ctx->play_state & STATE_EOF) return -1;
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);
*pts = ctx->audio_buffer[ctx->audio_ring.read].pts;
datalength = ctx->audio_buffer[ctx->audio_ring.read].size;
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;
}// AudioQueueOutputCallback
static int ct = 0;
static void fillAudioBuffer(void *info,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);
PlayState *ps = (PlayState *)info; if (!ps->started)
ps->started = true; while(buffer->mPacketDescriptionCount < numPacketsToRead && lengthCopied > 0)
{
lengthCopied = getNextAudio(_av,
buffer->mAudioDataBytesCapacity-buffer->mAudioDataByteSize,
(uint8_t*)buffer->mAudioData+buffer->mAudioDataByteSize,
&dts,&isDone); ct+= lengthCopied; if(lengthCopied < 0 || isDone)
{
printf("nothing to read....\n\n");
PlayState *ps = (PlayState *)info;
ps->finished = true;
ps->started = false;
break;
} if(aqStartDts < 0) aqStartDts = dts; if(buffer->mPacketDescriptionCount ==0)
{
bufferStartTime.mFlags = kAudioTimeStampSampleTimeValid;
bufferStartTime.mSampleTime = (Float64)(dts-aqStartDts);//* _av->audio.frame_size; if (bufferStartTime.mSampleTime <0 )
bufferStartTime.mSampleTime = 0; printf("AQHandler.m fillAudioBuffer: DTS for %x: %lf time base: %lf StartDTS: %d\n",
(unsigned int)buffer,
bufferStartTime.mSampleTime,
_av->audio.time_base,
aqStartDts); } buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mStartOffset = buffer->mAudioDataByteSize;
buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mDataByteSize = lengthCopied; buffer->mPacketDescriptions[buffer->mPacketDescriptionCount].mVariableFramesInPacket = 0; buffer->mPacketDescriptionCount++; buffer->mAudioDataByteSize += lengthCopied;
} int audioBufferCount, audioBufferTotal, videoBufferCount, videoBufferTotal;
bufferCheck(_av,&videoBufferCount, &videoBufferTotal, &audioBufferCount, &audioBufferTotal); if(buffer->mAudioDataByteSize)
{ err = AudioQueueEnqueueBufferWithParameters(queue, buffer, 0, NULL, 0, 0, 0, NULL, &bufferStartTime, NULL); if(err)
{
char sErr[10];
printf("AQHandler.m fillAudioBuffer: Could not enqueue buffer 0x%x: %d %s.", buffer, err, FormatError(sErr, err)); } }}