Kernel_Lover

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover  发布于  2018-03-08 09:57:45
采纳率 0%
17个问答
5129

mp4v2 录制音视频,视频播放速度慢

 
我用 mp4v2 录制音视频,录下来的 mp4 文件用暴风影音播放,发现音频是正常播放的,但是视频播放的速度比较慢,可以从录制视频右上方显示的时间看出来,当音频播放完毕后,就是没有声音了,只有图像,这时候视频才开始正常播放,导致音视频不同步,因为刚开始视频播放慢的原因。请问一下,这是什么原因?什么参数设置错了?谢谢!

我的代码:


#define VIDEO_TIME_SCALE 90000
#define FRAMES_PER_SECOND 25        // frame rate
#define BUFFER_SIZE  (1024 * 1024)
#define AUDIO_TIME_SCALE 44100


MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
MP4TrackId  audio = MP4_INVALID_TRACK_ID;
MP4TrackId  video = MP4_INVALID_TRACK_ID;

char isFirstSPS = 1;
char isFirstPPS = 1;

int mp4_init(void)
{
        unsigned char  data[2] = {0x12, 0x8};

        // 创建 mp4 文件 handler
        file = MP4Create("test_aac.mp4", 0);
        if (file == MP4_INVALID_FILE_HANDLE)
        {
                printf("create and open MP4 file failed!\n");
                return 0;
        }

        /* 添加音频 track */
        audio = MP4AddAudioTrack(file, AUDIO_TIME_SCALE, 320, MP4_MPEG4_AUDIO_TYPE);
        if (audio == MP4_INVALID_TRACK_ID)
        {
                printf("Add audio track failed!\n");
                return 0;
        }

        // 设置音频属性
        MP4SetAudioProfileLevel(file, 0x02);
        // unsigned char  data[2] = {0x12, 0x8};
        MP4SetTrackESConfiguration(file, audio, data, 2);

        return 1;       
}


void writeAACtoMP4(unsigned char *aac_buf, int len)
{       
        MP4WriteSample(file, audio, aac_buf + 7, len - 7, 320, 0, 1);                       
}


int writeH264toMP4(unsigned char *buffer, unsigned int frame_size)
{
        char nalu_type = buffer[4] & 0x1f;
        unsigned char *nalu_data = (unsigned char *) &buffer[4];
        unsigned int nalu_size = frame_size - 4;
       
        if(nalu_type == 0x07 && 1 == isFirstSPS) // sps   
        {   
                // 添加 h264 track   
                /* VIDEO_TIME_SCALE = 90000    FRAME_PESR_SECOND = 25 */   
                video = MP4AddH264VideoTrack   
                                    (   file,     
                                            VIDEO_TIME_SCALE,     
                                            VIDEO_TIME_SCALE / FRAME_PESR_SECOND,     
                                            1080,                             // width   
                                            720,                              // height   
                                            nalu_data[1],                 // sps[1] AVCProfileIndication   
                                            nalu_data[2],                 // sps[2] profile_compat   
                                            nalu_data[3],                 // sps[3] AVCLevelIndication   
                                            3);                             // 4 bytes length before each NAL unit   


                if (video == MP4_INVALID_TRACK_ID)   
                {   
                    printf("add video track failed.\n");   
                    return 0;   
                }  
          
                MP4SetVideoProfileLevel(file, 0x7f); //  Simple Profile @ Level 3   
                MP4AddH264SequenceParameterSet(file, video, nalu_data, nalu_size);  
                       
                isFirstSPS = 0;  
        }

        else if(nalu_type == 0x08 && 1 == isFirstPPS) // pps   
       {   
                MP4AddH264PictureParameterSet(file, video, nalu_data, nalu_size);

                isFirstPPS = 0;   
       }  

        else
       {   
                        // MP4 Nalu 前四个字节表示 Nalu 长度   
                        buffer[0] = nalu_size >> 24;   
                        buffer[1] = nalu_size >> 16;   
                         buffer[2] = nalu_size >> 8;   
                        buffer[3] = nalu_size & 0xff;
               
                           
                if(!MP4WriteSample(file, video, buffer, frame_size, 3600, 0, 1))
                {
                        printf("MP4WriteSample failed\n");
                            return 0;   
                }  
        }
        return 0;
}

我来回答
回答12个
时间排序
认可量排序

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-09 10:08:59
认可0
本帖最后由 Kernel_Lover 于 2018-3-12 09:57 编辑

int mp4_init(void)
{
        …………….
        /*  
                audio = MP4AddAudioTrack(file, AUDIO_TIME_SCALE, MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
                将第三个参数 MP4_INVALID_DURATION 改为 1024,使得视频的播放速度明显正常了许多,不是以前那么慢,
                当然还需要修改 MP4WriteSample 函数的参数才可以
       */
        audio = MP4AddAudioTrack(file, AUDIO_TIME_SCALE, 1024, MP4_MPEG4_AUDIO_TYPE);
        ……………
}


void writeAACtoMP4(unsigned char *aac_buf, int len)
{       
        /*
                MP4WriteSample(file, audio, aac_buf + 7, len - 7, 320, 0, 1);
               
                将 320 修改为 MP4_INVALID_DURATION
       */
        MP4WriteSample(file, audio, aac_buf + 7, len - 7, MP4_INVALID_DURATION, 0, 1);                       
}


经过上面的修改,视频播放速度明显正常了,不像以前播放速度慢,但是音视频还是不同步,音频会比较快播放完毕,只剩下视频。

WK12432

0个粉丝

0

问答

0

专栏

0

资料

WK12432 2018-03-10 09:32:55
认可0
本帖最后由 WK12432 于 2018-3-10 09:35 编辑

[quote][url=forum.php?mod=redirect&goto=findpost&pid=85074&ptid=39041]Kernel_Lover 发表于 2018-3-9 10:08[/url]
int mp4_init(void)
{
        …………….
[/quote]

应该就是时间戳和时基的问题,你前面调整的那个参数。

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-12 09:56:08
认可0
本帖最后由 Kernel_Lover 于 2018-3-12 10:46 编辑

[quote][url=forum.php?mod=redirect&goto=findpost&pid=85110&ptid=39041]WK12432 发表于 2018-3-10 09:32[/url]
应该就是时间戳和时基的问题,你前面调整的那个参数。[/quote]

确实要用到时间戳。对写入 mp4 的 h264 数据帧所用到的 duration 进行实时修改(第一个 h264 数据帧,使用的是固定值 3600,因为刚开始时,前一个帧的时间戳被初始化为 0,只有当前帧的时间戳),使用前一个数据帧和后一个数据帧的时间戳的差值。

获取当前 h264 数据帧的时间戳:

current_time =   rtp_buf[4] << 24;
current_time += rtp_buf[4] << 16;
current_time += rtp_buf[4] << 8;
current_time += rtp_buf[4][7];


int writeH264toMP4(unsigned char *buffer, unsigned int frame_size)
{
        char nalu_type = buffer[4] & 0x1f;
        unsigned char *nalu_data = (unsigned char *) &buffer[4];
        unsigned int nalu_size = frame_size - 4;
       
        if(nalu_type == 0x07 && 1 == isFirstSPS) // sps   
        //if(nalu.type == 0x07)
        {   
                .................
        }

        else if(nalu_type == 0x08 && 1 == isFirstPPS) // pps   
        //else if(nalu.type == 0x08)
            {   
                ..............
            }  

        else //if(nalu_type != 0x07 && nalu_type != 0x08)   
            {   
                       // MP4 Nalu 前四个字节表示 Nalu 长度   
                buffer[0] = nalu_size >> 24;   
                buffer[1] = nalu_size >> 16;   
                buffer[2] = nalu_size >> 8;   
                buffer[3] = nalu_size & 0xff;
                   /*
                        对于写入 mp4 文件的第一个 h264 数据帧,由于 prev_time = 0,只能特殊处理,
                        指定 duration = 3600 = 90000 / 25
                */
                    if(1 == isFirstFrame)   
                    {
                        if(!MP4WriteSample(file, video, buffer, frame_size, 3600, 0, 1))  
                        //if(!MP4WriteSample(file, video, buffer, frame_size, MP4_INVALID_DURATION, 0, 1))  
                        {
                                printf("MP4WriteSample failed\n");
                            return 0;   
                        }
                        /* 已经不是第一个写入 mp4 文件的 h264 数据帧 */
                        isFirstFrame = 0;
                        /* 设置前一帧的时间戳 */
                        prev_time = current_time;
                }   

                else
                {
                        printf("current_time - prev_time = %u\n", current_time - prev_time);
                        /*
                                duration = current_time - prev_time

                                rtp 数据包的时间戳是没有指定单位的,是和 rtp 数据包所携带的数据类型有关。但是通过打印发现,
                                对于 h264 数据帧,时间戳的单位是 1秒 / 90000,正好符合我们设置的采样频率为 90000
                        */
                        if(!MP4WriteSample(file, video, buffer, frame_size, current_time - prev_time, 0, 1))  
                        //if(!MP4WriteSample(file, video, buffer, frame_size, MP4_INVALID_DURATION, 0, 1))  
                        {
                                printf("MP4WriteSample failed\n");
                                    return 0;   
                        }  
                        /* 设置前一帧的时间戳 */
                        prev_time = current_time;
                }  
        }

        return 0;
}

在录制的两分半的 mp4 文件中,音频播放完毕后,视频还会播放2秒左右。
在7分半的 mp4 文件中,音频播放完毕后,视频也还会播放2秒左右,甚至还少于两秒。
在25分钟左右的 mp4 文件中,音频播放完毕后,视频也还会播放2秒左右。

这好像说明音视频是同步的,可能是刚开始因为视频线程和音频线程的启动时间不同,导致音视频总是差着2秒左右。或者关闭进程时,音频和视频的关闭时间不同,使得视频或音频多录了2秒左右。还没有去验证,但是基本上是同步了。



zjx94

0个粉丝

7

问答

0

专栏

0

资料

zjx94 2018-03-17 10:31:52
认可0
?????
楼主不调用这个MP4SetTimeScale 函数来设置时间标量???

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-19 11:06:42
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85454&ptid=39041]zjx94 发表于 2018-3-17 10:31[/url]
?????
楼主不调用这个MP4SetTimeScale 函数来设置时间标量???[/quote]

可以不使用这个函数,在添加 track 就已经设置了

zjx94

0个粉丝

7

问答

0

专栏

0

资料

zjx94 2018-03-19 17:07:42
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85482&ptid=39041]Kernel_Lover 发表于 2018-3-19 11:06[/url]
可以不使用这个函数,在添加 track 就已经设置了[/quote]

你确定?起码网上例子很多都加有。我的也有,既然你的程序有问题,何不试试

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-20 13:47:32
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85505&ptid=39041]zjx94 发表于 2018-3-19 17:07[/url]
你确定?起码网上例子很多都加有。我的也有,既然你的程序有问题,何不试试[/quote]

我的程序基本是同步了,如果使用 MP4SetTimeScale 函数来设置时间标量,视频和音频的时间标量是不一样的,就只能设置视频的时间标量或者音频的时间标量

zjx94

0个粉丝

7

问答

0

专栏

0

资料

zjx94 2018-03-20 14:13:51
认可0
本帖最后由 zjx94 于 2018-3-20 14:15 编辑

MP4SetTimeScale(MP4V2_file, 90000);
//video
MP4AddH264VideoTrack(handle->mp4_file, 48000, 1920, 1920, 1080,...............
           MP4WriteSample(rhandle->mp4_file, m_vTrackId,pkt->data,pkt->size, 48000/fps, 0, 1);
//audio
MP4AddAudioTrack(handle->mp4_file, 48000, 1024,.........
        MP4WriteSample(rhandle->mp4_file, mp4v2_audio,pkt->data ,pkt->size, MP4_INVALID_DURATION, 0, 1);

zjx94

0个粉丝

7

问答

0

专栏

0

资料

zjx94 2018-03-20 14:16:47
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85542&ptid=39041]Kernel_Lover 发表于 2018-3-20 13:47[/url]
我的程序基本是同步了,如果使用 MP4SetTimeScale 函数来设置时间标量,视频和音频的时间标量是不一样的 ...[/quote]

同步就是同步,没有基本同步这种东西,你参考看看我写的。

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-20 14:35:28
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85544&ptid=39041]zjx94 发表于 2018-3-20 14:13[/url]
MP4SetTimeScale(MP4V2_file, 90000);
//video
MP4AddH264VideoTrack(handle->mp4_file, 48000, 1920, 19 ...[/quote]

层主,48000 / fps 中的 fps 看起来应该是一个常量,还是通过时间戳得到的?

zjx94

0个粉丝

7

问答

0

专栏

0

资料

zjx94 2018-03-20 14:52:50
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85548&ptid=39041]Kernel_Lover 发表于 2018-3-20 14:35[/url]
层主,48000 / fps 中的 fps 看起来应该是一个常量,还是通过时间戳得到的?[/quote]

就是 帧数 ,你可以先按照你的帧数来

Kernel_Lover

0个粉丝

17

问答

0

专栏

0

资料

Kernel_Lover 2018-03-20 14:54:45
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=85550&ptid=39041]zjx94 发表于 2018-3-20 14:52[/url]
就是 帧数 ,你可以先按照你的帧数来[/quote]

好的,谢谢了!
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区