首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用自定义视频编写程序库编写音频的错误

使用自定义视频编写程序库编写音频的错误
EN

Stack Overflow用户
提问于 2018-05-07 02:48:16
回答 2查看 390关注 0票数 6

我试图包装一小块方便的C++代码,该代码旨在使用VFW在windows上生成video+audio,C++库lives 这里,描述如下:

为Windows使用视频(因此它不是可移植的)。如果您想在某个地方快速录制一段视频,并且不想自己费力地浏览VfW文档,这很方便。

我想使用Python上的C++库,所以我决定使用swig结束它。

问题是,当涉及到音频编码时,我遇到了一些问题,由于某种原因,我试图理解为什么生成的视频被破坏了,似乎音频没有被正确地写入视频文件中。这意味着,如果我尝试用VLC或任何类似的视频播放器打开视频,我会收到一条消息,说视频播放器无法识别音频或视频编解码器。视频图像是好的,所以这肯定是一个问题,我写音频到文件的方式。

我同时附加了swig接口和一个小Python测试,试图成为原始c++测试的一个端口。

aviwriter.i

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
%module aviwriter

%{
#include "aviwriter.h"
%}

%typemap(in) (const unsigned char* buffer) (char* buffer, Py_ssize_t length) %{
  if(PyBytes_AsStringAndSize($input,&buffer,&length) == -1)
    SWIG_fail;
  $1 = (unsigned char*)buffer;
%}

%typemap(in) (const void* buffer) (char* buffer, Py_ssize_t length) %{
  if(PyBytes_AsStringAndSize($input,&buffer,&length) == -1)
    SWIG_fail;
  $1 = (void*)buffer;
%}


%include "aviwriter.h"

test.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import argparse
import sys
import struct
from distutils.util import strtobool

from aviwriter import AVIWriter


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-audio", action="store", default="1")
    parser.add_argument('-width', action="store",
                        dest="width", type=int, default=400)
    parser.add_argument('-height', action="store",
                        dest="height", type=int, default=300)
    parser.add_argument('-numframes', action="store",
                        dest="numframes", type=int, default=256)
    parser.add_argument('-framerate', action="store",
                        dest="framerate", type=int, default=60)
    parser.add_argument('-output', action="store",
                        dest="output", type=str, default="checker.avi")

    args = parser.parse_args()

    audio = strtobool(args.audio)
    framerate = args.framerate
    num_frames = args.numframes
    width = args.width
    height = args.height
    output = args.output

    writer = AVIWriter()

    if not writer.Init(output, framerate):
        print("Couldn't open video file!")
        sys.exit(1)

    writer.SetSize(width, height)

    data = [0]*width*height
    sampleRate = 44100
    samples_per_frame = 44100 / framerate
    samples = [0]*int(samples_per_frame)

    c1, s1, f1 = 24000.0, 0.0, 0.03
    c2, s2, f2 = 1.0, 0.0, 0.0013

    for frame in range(num_frames):
        print(f"frame {frame}")

        i = 0
        for y in range(height):
            for x in range(width):
                on = ((x + frame) & 32) ^ ((y+frame) & 32)
                data[i] = 0xffffffff if on else 0xff000000
                i += 1
        writer.WriteFrame(
            struct.pack(f'{len(data)}L', *data),
            width*4
        )

        if audio:
            for i in range(int(samples_per_frame)):
                c1 -= f1*s1
                s1 += f1*c1
                c2 += f2*s2
                s2 -= f2*c2

                val = s1 * (0.75 + 0.25 * c2)
                if(frame == num_frames - 1):
                    val *= 1.0 * (samples_per_frame - 1 - i) / \
                        samples_per_frame
                samples[i] = int(val)

                if frame==0:
                    print(f"i={i} val={int(val)}")

            writer.WriteAudioFrame(
                struct.pack(f'{len(samples)}i', *samples),
                int(samples_per_frame)
            )

    writer.Exit()

我并不认为samples的生成是错误的,因为我已经将在python端生成的值与在c++端生成的值进行了比较,只是为框架0编写的包。

我对出了什么问题的一些怀疑是我在酒杯上创建打字机地图的方式,也许这不太好.或者问题就在writer.WriteAudioFrame(struct.pack(f'{len(samples)}i', *samples), int(samples_per_frame))中,我不知道会发生什么,我将音频缓冲区从C++发送到C++包装器的方式肯定不是很好。

那么,您是否知道如何修复附加的代码,以便test.py能够生成与c++测试类似的正确音频的视频?

当生成ok时,视频将显示一个神奇的滚动棋盘,以催眠的正弦波作为音频背景:D

附加注释:

( 1)上述代码似乎不使用writer.SetAudioFormatAVIFileCreateStreamAAVIStreamSetFormat函数需要使用AVIStreamSetFormat。问题是,我不知道如何在swig上导出这个结构,这样我就可以在Python上以与test.cpp相同的方式使用它,从Mmreg.h我看到了这样的结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct tWAVEFORMATEX
{
    WORD    wFormatTag;        /* format type */
    WORD    nChannels;         /* number of channels (i.e. mono, stereo...) */
    DWORD   nSamplesPerSec;    /* sample rate */
    DWORD   nAvgBytesPerSec;   /* for buffer estimation */
    WORD    nBlockAlign;       /* block size of data */
    WORD    wBitsPerSample;    /* Number of bits per sample of mono data */
    WORD    cbSize;            /* The count in bytes of the size of
                                    extra information (after cbSize) */

} WAVEFORMATEX;

不幸的是,我不知道如何将这些东西包装在导航器上。我试过使用%include windows.i并将其直接包含在块%{.%}上,但我所得到的只是一堆错误:/

2)我完全不喜欢修改aviwriter.h & aviwriter.cpp,因为这基本上是外部工作代码。

3)假设我能够包装WAVEFORMATEX以便可以在Python上使用它,那么您如何使用memset类似于test.cpp呢?ie:memset(&wfx,0,sizeof(wfx));

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-13 23:11:18

有两项建议:

  • 首先,按照short测试,将数据打包为int格式,而不是音频格式的数据。音频数据是16位,而不是32位。对包装格式使用“h”分机。例如,struct.pack(f'{len(samples)}h', *samples)
  • 第二,请参见下面的代码修改。通过SWIG公开WAVEFORMATX,编辑aviwriter.i。然后从Python调用writer.SetAudioFormat(wfx)
  • 在我的测试中,memset()是不必要的。在python中,您可以手动将字段cbSize设置为零,这应该足够了。其他六个字段是强制性的,所以无论如何都要设置它们。这个结构看起来不打算在将来进行修改,因为它没有一个struct字段,而且cbSize的语义(将任意数据附加到结构的末尾)与扩展也有冲突。

航空公司:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
%inline %{
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef struct tWAVEFORMATEX
{
    WORD    wFormatTag;        /* format type */
    WORD    nChannels;         /* number of channels (i.e. mono, stereo...) */
    DWORD   nSamplesPerSec;    /* sample rate */
    DWORD   nAvgBytesPerSec;   /* for buffer estimation */
    WORD    nBlockAlign;       /* block size of data */
    WORD    wBitsPerSample;    /* Number of bits per sample of mono data */    
    WORD    cbSize;            /* The count in bytes of the size of
                                extra information (after cbSize) */
} WAVEFORMATEX;
%}

test.py:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from aviwriter import WAVEFORMATEX

稍后在test.py中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    wfx = WAVEFORMATEX()
    wfx.wFormatTag = 1 #WAVE_FORMAT_PCM
    wfx.nChannels = 1
    wfx.nSamplesPerSec = sampleRate
    wfx.nAvgBytesPerSec = sampleRate * 2
    wfx.nBlockAlign = 2
    wfx.wBitsPerSample = 16
    writer.SetAudioFormat(wfx)

注释:,因为aviwriter.h只提供tWAVEFORMATEX的前向声明,没有向tWAVEFORMATEX提供其他信息,从而阻止生成get/set包装器。您可以要求SWIG包装一个声明结构的Windows报头.打开一罐蠕虫,因为这些头太大太复杂,暴露了更多的问题。相反,您可以像上面所做的那样分别定义WAVEFORMATEX。不过,C++类型WORDDWORD仍未声明。包含SWIG文件windows.i只创建包装器,例如,它允许将Python文件中的字符串"WORD“理解为表示内存中的16位数据。但这并不是从WORD的角度来声明C++类型。要解决这个问题,在这个WORD语句中添加%inlineDWORD的类型,aviwriter.i将强制SWIG将代码直接内联到包装器C++文件中,使声明可用。这还会触发生成get/set包装器。或者,如果您愿意编辑,可以将内联的代码包含在aviwriter.h中。

简而言之,这里的想法是将所有类型完全封装到独立的头或声明块中。请记住,.i和.h文件有单独的功能(包装器和数据转换,而不是包装的功能)。类似地,请注意如何在aviwriter.h中包含两次aviwriter.i,一次用于触发C++所需的包装器的生成,一次是在C++所需的生成的包装代码中声明类型。

票数 5
EN

Stack Overflow用户

发布于 2018-05-13 00:09:33

根据我在代码中看到的,您没有初始化音频格式。这是在原始test.cpp代码中通过在第44行调用writer.SetAudioFormat(&wfx);来完成的,然后将其设置为mono44.1 kHz PCM。我相信,由于您不初始化,空白标题是写的,并且视频播放器无法打开未知的格式。

更新

因为您只需要传递二进制头结构,并且不需要使用该结构并在aviwriter.i中声明它。您可以直接从Python中使用以下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import struct
from collection import namedtuple

WAVEFORMATEX = namedtuple('WAVEFORMATEX', 'wFormatTag nChannels nSamplesPerSec nAvgBytesPerSec nBlockAlign wBitsPerSample cbSize ')
wfx = WAVEFORMATEX(    
    wFormatTag = 1,
    nChannels = 1,
    nSamplesPerSec = sampleRate,
    nAvgBytesPerSec = sampleRate * 2,
    nBlockAlign = 2,
    wBitsPerSample = 16,
    cbSize = 0)

audio_format_obj = struct.pack('<HHIIHHH', *list(wfx))
writer.SetAudioFormat(audio_format_obj)            

这将自动解决您的第二和第三个问题。

至于memset(&wfx,0,sizeof(wfx));,这只是旧C实现结构中所有变量的零的一种丑陋的方式。

正如@MichaelsonBritt所提到的,您的音频数据格式必须与报头中的声明相匹配。但与其转换为16位short,你可以声明两个频道,所以你将得到立体声声音与一个频道静音。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50212416

复制
相关文章
Apache URL重写规则
  Apached的重写功能,即是mod_rewrite模块功能,它是apache的一个模块。它的功能非常强大,可以操作URL中的所有部分。
那一叶随风
2018/08/22
3K0
Apache URL重写规则
安装和使用IIS的URL重写工具
这几天正在忙自己的个人网站,遇到一个需求,就是把普通的http请求全部转发到https上。百度得知,使用默认的IIS功能无法做到这一点,必须安装一个额外的工具:URL重写工具。但是默认没有安装。这里就来先安装一下。
乐百川
2022/05/05
2.7K0
IIS虚拟主机支持URL重写指南
IIS虚拟主机支持.htaccess实现URL重写,下载合适的版本,下载手动安装包ISAPI_Rewrite3_0042_manual.exe,需要手工解压到服务器的一个目录中。
会长君
2023/04/26
4.4K0
IIS URL文件名有加号或空格显示404错误的解决办法
请求筛选模块被配置为拒绝包含双重转义序列的请求。HTTP 错误 404.11 - Not Found
2021/11/08
1.2K0
IIS URL文件名有加号或空格显示404错误的解决办法
URL重写
(图片来自:https://github.com/Bikeman868/UrlRewrite.Net)
问问计算机
2021/05/08
5K0
URL重写
WINDOWS网站IIS可以URL重写到站外的方式即IIS反向代理
iis现在都提供URL重写模块,可以在站内任意跳转,但我们相跳转到别的站点该怎么办呢?
睿儿网络郝刚
2020/09/08
3K0
WINDOWS网站IIS可以URL重写到站外的方式即IIS反向代理
iis站点设置错误页面返回http状态码为404而不是302或其他
  今天一位客户说网站错误页面返回的状态码是302而不是404,问ytkah要如何处理。这个应该是设置没有正确的原因。我们一步步来排查一下。1、首先打开iis管理器,左侧选择具体的站点,在右侧窗口中点击404错误页,如下图所示
ytkah
2019/09/25
3.3K0
iis站点设置错误页面返回http状态码为404而不是302或其他
IIS进行URL重写——实现https重定向,文件类型隐藏访问重写,nodejs等服务重写等等
一、Why? 1、先来讲一讲为什么我们要使用url重写这个东西 2、因为我学习的后端是nodejs,然后我发现nodejs一个非常让人难受的事,就是它监听端口不是80和443时,你访问网页需要输入端口
SpiritLing
2018/04/16
15.3K2
IIS进行URL重写——实现https重定向,文件类型隐藏访问重写,nodejs等服务重写等等
Url Rewrite 再说Url 重写
前几天看到园子里一篇关于 Url 重写的文章《获取ISAPI_Rewrite重写后的URL》 , URL-Rewrite 这项技术早已不是一项新技术了,这个话题也已经被很多人讨论过多次。搜索一下URL-Rewrite可以找到很多URL-Rewrite方面的文章和组件,自己以前也多次接触过这个东东,也来说说吧。 ScottGu 有一篇非常经典的 URL-Rewrite Blog Tip/Trick: Url Rewriting with ASP.NET http://weblogs.asp.net/scot
葡萄城控件
2018/01/10
4.6K0
Url Rewrite 再说Url 重写
Nginx url 重写
和apache等web服务软件一样,rewrite的主要功能是实现URL地址的重定向。Nginx的rewrite功能需要PCRE软件的支持,即通过perl兼容正则表达式语句进行规则匹配的。默认参数编译nginx就会支持rewrite的模块,但是也必须要PCRE的支持。
星哥玩云
2022/09/15
2.6K0
Nginx url 重写
Nginx URL重写
rewite 规则作用 Rewrite规则可以实现对url的重写,以及重定向 --作用场景 URL访问跳转,支持开发设计,如页面跳转,兼容性支持,展示效果等 SEO优化 维护:后台维护、流量转发等 安全 rewrite 语法 rewrite <regex> <replacement> [flag]; 关键字 正则 替代内容 flag标记 --解释 关键字 其中关键字error_log不能改变 正则 perl兼容正
剧终
2020/12/31
1.1K0
windows2003为iis添加伪静态规则
最近开始使用一个新的cms,网站由于是基于thinkphp开发的,而服务器还是古老的windows2003,所以一些伪静态的问题导致网站始终安装不成功。 可能以后不会用到了,这里还是记录下解决的办法
用户1188347
2018/02/27
2.7K0
windows2003为iis添加伪静态规则
IIRF(Ionics Isapi Rewrite Filt er)实现在IIS 5/6上重写Url
IIS 7的URL Rewrite功能非常强大,可以通过Microsoft URL Rewrite Module来实现,可参看文章使用Microsoft URL Rewrite Module for IIS 7.0修改WEB.CONFIG即可实现*.HTML伪静态 无需修改应用程序映射。 IIS 5/6的URL Rewrite也可以通过IIRF(Ionic's Isapi Rewrite Filter)来实现。IIRF(Ionic's Isapi Rewrite Filter)是一款开源的重写URL过滤器,
张善友
2018/01/30
1.7K0
springMVC的url重写
 1.利用maven下载相关jar文件,pom文件配置如下:
似水的流年
2018/01/14
1.2K0
nginx配置url重写
url重写是指通过配置conf文件,以让网站的url中达到某种状态时则定向/跳转到某个规则,比如常见的伪静态、301重定向、浏览器定向等
landv
2020/03/03
2.5K0
springMVC的url重写
3.添加urlrewirte.xml文件,将文件放在WEB-INF目录下(貌似该文件只能放在WEB-INF下)。配置如下:
似水的流年
2019/12/11
1.1K0
nginx配置url重写
url重写是指通过配置conf文件,以让网站的url中达到某种状态时则定向/跳转到某个规则,比如常见的伪静态、301重定向、浏览器定向等
PM吃瓜
2019/08/13
1.8K0
.htaccess的重写规则
.htaccess是Apache服务器的一个非常强大的分布式配置文件。 正确的理解和使用.htaccess文件,可以帮助我们优化自己的服务器或者虚拟主机。
Java架构师必看
2021/03/22
1.9K0
springMVC的url重写
 1.利用maven下载相关jar文件,pom文件配置如下: <dependency> <groupId>org.tuckey</groupId> <artifactId>urlrewritefilter</artifactId> <version>3.2.0</version> </dependency> 2.在web.xml中配置UrlRewriteFilter,配置如下:         <!--urlrewrite过滤器-
似水的流年
2018/01/18
1.4K0
搜索优化:利用IIS的URL重写模块配置IIS让不带www的域名永久301到www上面。
在对网站做优化的时候通常会让不带www的域名如zjkdh.com永久301到自已要优化的域名上面,如(www.zjkdh.com),这么做就是为了集权,把所有域名的权重集到一个上面,这样的话有可能会使你域名的权重更集中,不分散,这种前提下有可能会比不处理的情况涨的多一些。
睿儿网络郝刚
2020/09/08
3.3K0
搜索优化:利用IIS的URL重写模块配置IIS让不带www的域名永久301到www上面。

相似问题

Url重写规则导致404错误

12

IIS重写不工作- 404错误

23

IIS Url重写规则

13

IIS URL重写规则- IIS 7

12

IIS 8重写规则显示404错误

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文