2301_81955753 2024-12-02 17:20 采纳率: 50%
浏览 49
已结题

如何在音频中嵌入字符串(水印)信息进行传递

有一个特殊场景需要在一段音频里面嵌入字符串,类似声音领域的水印。
要求:
(一)尽量减少对原音频的影响;
(二)其他设备通过话筒、录音接收到音频后,能够从中提取出“水印”信息

我自己研究了一下,本来是打算在20000赫兹的地方嵌入信息,但是环境嘈杂会影响读取


```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Audio Data Transmission</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .container {
            max-width: 600px;
            margin: auto;
        }
        .section {
            margin-bottom: 20px;
        }
        button {
            padding: 10px 20px;
            font-size: 16px;
        }
        #outputText {
            white-space: pre-wrap;
            border: 1px solid #ccc;
            padding: 10px;
            min-height: 100px;
        }
        canvas {
            display: block;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Audio Data Transmission</h1>
        
        <!-- Sender Section -->
        <div class="section">
            <h2>Send Data</h2>
            <input type="text" id="inputText" placeholder="Enter text to send">
            <button onclick="sendData()">Send</button>
            <canvas id="senderSpectrum" width="600" height="100"></canvas>
        </div>
        
        <!-- Receiver Section -->
        <div class="section">
            <h2>Receive Data</h2>
            <p id="outputText"></p>
            <canvas id="receiverSpectrum" width="600" height="100"></canvas>
        </div>
    </div>

    <script>
        let isSending = false;
        let receivedBits = '';
        let receivedData = '';

        function sendData() {
            if (isSending) {
                alert("Already sending data. Please wait.");
                return;
            }
            isSending = true;
            const text = document.getElementById('inputText').value;
            const binaryData = stringToBinary(text) + '00000000'; // Add end of transmission marker
            modulateAndPlay(binaryData);
        }

        function stringToBinary(str) {
            return str.split('').map(char => char.charCodeAt(0).toString(2).padStart(8, '0')).join('');
        }

        function modulateAndPlay(binaryData) {
            const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            const oscillator = audioCtx.createOscillator();
            oscillator.type = 'sine';
            oscillator.frequency.setValueAtTime(20000, audioCtx.currentTime);

            const gainNode = audioCtx.createGain();
            gainNode.gain.value = 0;

            oscillator.connect(gainNode);
            gainNode.connect(audioCtx.destination);

            // Create an AnalyserNode to get frequency data
            const analyser = audioCtx.createAnalyser();
            analyser.fftSize = 2048;
            gainNode.connect(analyser);

            const bufferLength = analyser.frequencyBinCount;
            const dataArray = new Uint8Array(bufferLength);

            // Get the canvas context for drawing the spectrum
            const canvas = document.getElementById('senderSpectrum');
            const canvasCtx = canvas.getContext('2d');

            let index = 0;
            const interval = setInterval(() => {
                if (index < binaryData.length) {
                    gainNode.gain.value = binaryData[index] === '1' ? 0.5 : 0;
                    index++;
                } else {
                    clearInterval(interval);
                    oscillator.stop();
                    isSending = false;
                }
            }, 100); // Adjust the timing as needed

            oscillator.start();

            function drawSpectrum() {
                analyser.getByteFrequencyData(dataArray);

                canvasCtx.fillStyle = 'rgb(0, 0, 0)';
                canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

                const barWidth = canvas.width / bufferLength;
                let barHeight;

                for(let i = 0; i < bufferLength; i++) {
                    barHeight = dataArray[i];

                    canvasCtx.fillStyle = 'rgb(' + (barHeight + 100) + ',50,50)';
                    canvasCtx.fillRect(i * barWidth, canvas.height - barHeight, barWidth, barHeight);
                }

                requestAnimationFrame(drawSpectrum);
            }

            drawSpectrum();
        }

        navigator.mediaDevices.getUserMedia({ audio: true })
            .then(stream => {
                const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
                const source = audioCtx.createMediaStreamSource(stream);
                const analyser = audioCtx.createAnalyser();
                source.connect(analyser);

                analyser.fftSize = 2048;
                const bufferLength = analyser.frequencyBinCount;
                const dataArray = new Uint8Array(bufferLength);

                // Get the canvas context for drawing the spectrum
                const canvas = document.getElementById('receiverSpectrum');
                const canvasCtx = canvas.getContext('2d');

                function detectSignal() {
                    analyser.getByteFrequencyData(dataArray);
                    const targetIndex = Math.round(20000 * (bufferLength / audioCtx.sampleRate));
                    const amplitude = dataArray[targetIndex];

                    if (amplitude > 128) { // Threshold for detecting a '1'
                        receivedBits += '1';
                    } else {
                        receivedBits += '0';
                    }

                    if (receivedBits.length >= 8) {
                        const byte = receivedBits.slice(0, 8);
                        receivedBits = receivedBits.slice(8);
                        const charCode = parseInt(byte, 2);
                        if (charCode === 0) {
                            // End of transmission marker
                            const receivedText = binaryToString(receivedData);
                            document.getElementById('outputText').innerText = receivedText;
                            receivedData = '';
                        } else {
                            receivedData += String.fromCharCode(charCode);
                        }
                    }

                    // Draw the spectrum
                    canvasCtx.fillStyle = 'rgb(0, 0, 0)';
                    canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

                    const barWidth = canvas.width / bufferLength;

                    for(let i = 0; i < bufferLength; i++) {
                        barHeight = dataArray[i];

                        canvasCtx.fillStyle = 'rgb(' + (barHeight + 100) + ',50,50)';
                        canvasCtx.fillRect(i * barWidth, canvas.height - barHeight, barWidth, barHeight);
                    }

                    requestAnimationFrame(detectSignal);
                }

                detectSignal();
            })
            .catch(err => console.error("The following error occurred: " + err));

        function binaryToString(binary) {
            if (!binary || binary.length % 8 !== 0) {
                console.warn("Invalid binary string length:", binary.length);
                return '';
            }
            return binary.match(/.{8}/g).map(byte => String.fromCharCode(parseInt(byte, 2))).join('');
        }
    </script>
</body>
</html>

```

  • 写回答

26条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-12-02 17:20
    关注

    以下回复引自免费微信小程序:皆我百晓生。 如问题解决,还请采纳。如仍有疑问,请回复留言或私信博主,以便获得更精准的帮助。

    解决此问题的方法:

    1. 使用PYTHON的内置库来读取音频文件。
    2. 从音频文件中提取出水印信息。
    3. 将水印信息插入到音频文件的适当位置。

    以下是一个简单的示例代码:

    IMPORT WAVE
    FROM PYDUB IMPORT AUDIOSEGMENT
    
    # 读取音频文件
    FILE = 'YOUR_AUDIO_FILE.WAV'
    AUDIO = AUDIOSEGMENT.FROM_WAV(FILE)
    
    # 提取水印信息
    WATERMARK_INFO = AUDIO.GET_FRAME(0).GET_WATERMARK()
    
    # 打开剪裁好的音频文件
    WAVE_FILE = WAVE.OPEN('YOUR_AUDIO_FILE.WAV', 'RB')
    
    # 转换为流
    STREAM = WAVE_FILE.READFRAMES(WAVE_FILE.GETNFRAMES())
    
    # 在指定位置插入水印信息
    FOR I IN RANGE(LEN(STREAM) - LEN(WATERMARK_INFO) + 1):
        STREAM[I:I+LEN(WATERMARK_INFO)] += WATERMARK_INFO
    
    # 再次转换回流
    STREAM.SEEK(0)
    WAVE_FILE.WRITEFRAMES(STREAM.GETVALUE())
    WAVE_FILE.CLOSE()
    

    请注意,这段代码仅用于演示目的,并没有实际实现水印的功能。在实际应用中,你可能需要使用不同的方法来处理水印,例如将水印保存在本地文件中或者发送给第三方平台。此外,这段代码可能会受到音频质量的影响,因此可能需要调整音量和采样率以获得最佳效果。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月9日
  • 创建了问题 12月2日

悬赏问题

  • ¥15 宇视监控服务器无法登录
  • ¥15 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥50 power BI 从Mysql服务器导入数据,但连接进去后显示表无数据
  • ¥15 (关键词-阻抗匹配,HFSS,RFID标签天线)