Issues arising when routing ffmpeg to flac encoder

I am facing an issue with encoding a flac file with seektables. The ffmpeg's flac encoder does not include seektables, so I have to resort to using the flac Command Line Interface (CLI). My goal is to convert any arbitrary audio file into a seekable flac file by first passing it through ffmpeg and then through the flac encoder.

export const transcodeToFlac: AudioTranscoder<{}> = ({
  source,
  destination
}) => {
  return new Promise((resolve, reject) => {
    let totalSize = 0

    const { stdout: ffmpegOutput, stderr: ffmpegError } = spawn("ffmpeg", [
      "-i",
      source,
      "-f",
      "wav",
      "pipe:1"
    ])

    const { stdout: flacOutput, stdin: flacInput, stderr: flacError } = spawn(
      "flac",
      ["-"]
    )

    flacOutput.on("data", (buffer: Buffer) => {
      totalSize += buffer.byteLength
    })

    ffmpegError.on("data", error => {
      console.log(error.toString())
    })

    flacError.on("data", error => {
      console.log(error.toString())
    })

    //stream.on("error", reject)

    destination.on("finish", () => {
      resolve({
        mime: "audio/flac",
        size: totalSize,
        codec: "flac",
        bitdepth: 16,
        ext: "flac"
      })
    })

    ffmpegOutput.pipe(flacInput)
    flacOutput.pipe(destination)
  })
}

Although the above code appears to be working, there seems to be an issue in the resulting flac file. The duration of the source audio is 06:14, but the flac file shows a duration of 06:45:47. Manual encoding of the flac without piping ffmpeg works perfectly fine, however, in a server environment where stream utilization is necessary, this approach cannot work effectively.

The following output is provided by the flac encoder during transcoding:

flac 1.3.2
Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation
flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
welcome to redistribute it under certain conditions.  Type `flac' for details.

-: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
-: WARNING, cannot write back seekpoints when encoding to stdout
-: 0% complete, ratio=0.357
0% complete, ratio=0.432
0% complete, ratio=0.482
0% complete, ratio=0.527
0% complete, ratio=0.541
1% complete, ratio=0.554
1% complete, ratio=0.563
1% complete, ratio=0.571
size=   36297kB time=00:03:30.70 bitrate=1411.2kbits/s speed= 421x
1% complete, ratio=0.572
1% complete, ratio=0.570
1% complete, ratio=0.577
1% complete, ratio=0.583
1% complete, ratio=0.584
1% complete, ratio=0.590
1% complete, ratio=0.592
size=   64512kB time=00:06:14.49 bitrate=1411.2kbits/s speed= 421x
video:0kB audio:64512kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead:
0.000185%

-: WARNING: unexpected EOF; expected 1073741823 samples, got 16510976 samples
2% complete, ratio=0.579

Answer №1

Let's start with the basics:

I have to encode a flac file with seektables,

-: WARNING, cannot write back seekpoints when encoding to stdout

According to flac -H:

A single INPUTFILE may be - for stdin. No INPUTFILE implies stdin. Use of
stdin implies -c (write to stdout). Normally you should use:
   flac [options] -o outfilename or flac -d [options] -o outfilename
instead of:
   flac [options] > outfilename or flac -d [options] > outfilename
since the former allows flac to seek backwards to write the STREAMINFO or
WAVE/AIFF header contents when necessary.

Try using flac - -o outfilename.flac instead of just flac -

It seems to work for me and the resulting audio is of correct length (in my case - which is different from yours though):

$ rm out.flac; ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav - | flac - -o out.flac


flac 1.3.2
Copyright (C) 2000-2009 Josh Coalson, 2011-2016 Xiph.Org Foundation
flac comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
welcome to redistribute it under certain conditions. Type `flac' for details.

ffmpeg version n4.1.3 Copyright (c) 2000-2019 the FFmpeg developers
...

This

-: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)

can't be helped:
ERROR: --keep-foreign-metadata cannot be used when encoding from stdin or to stdout

Despite getting

-: WARNING: unexpected EOF; expected 1073741823 samples, got 141516800 samples

which caused the process to stop at 13% (141516800 * 100 / 1073741823 = 13.2%), the output appears to be fine and matches the input's length!

UPDATE: This issue arises because ffmpeg fails to fill in the correct ChunkSize value of the output wav due to sending data to a pipe rather than a file, preventing it from updating the ChunkSize after encoding completes. When writing to a file, this isn't an issue.

The canonical WAVE format starts with the RIFF header:

0         4   ChunkID          Contains the letters "RIFF" in ASCII form
                               (0x52494646 big-endian form).
4         4   ChunkSize        36 + SubChunk2Size, or more precisely:
...

Here's how ffmpeg's wav output differs between file and pipe outputs:

(note: do not execute this command as it consumes significant CPU resources)

$ colordiff -up <(hexdump -C toafile.wav) <(hexdump -C piped.wav)
...
  1. The piped wav file (generated by ffmpeg) triggers one extra warning from flac:

a. Generate a piped wav:

ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav - > piped.wav

b. Feed into flac:

cat piped.wav | flac - -o out2.flac

flac 1.3.2
...

Flac does not have the correct input size information (ChunkSize is 0xFFFFFFFF)

  1. On the other hand, the wav file generated by ffmpeg for file output works well:

a. Create a wav file:

ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav toafile.wav

b. Feed into flac:

$ rm out2.flac; cat toafile.wav | flac - -o out2.flac

flac 1.3.2
...

Success is achieved as the ChunkSize value is accurate (ChunkSize is 0x21BDC046 = 566,083,654 bytes, only 8 bytes less compared to infile.wav total size of 566,083,662 bytes)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to implement type discrimination in TypeScript?

When using TypeScript with two interfaces combined as a union type, why doesn't it distinguish which type members can be declared? interface IFish { swim: () => void; } interface ICat { meow: () => void; } type Pet = IFish | ICat; const p ...

Ways to modify this request in order to update the current status

How can I optimize these calls to avoid repeating the same sentence for refreshing the state? I'm not looking for a major overhaul, just some suggestions like putting this call inside a function and invoking it when needed... export const CategoriesPa ...

Is it possible to create and manage a hierarchical menu in React (Next.js) using a generic approach?

Over the past few days, I've been working on a project involving a navigation bar built with TypeScript and React (Next.js). Up until now, I've only had a single level navigation, but now I'm looking to upgrade to a multi-level navigation me ...

What does the reportProgress function do in HTTP services with JavaScript?

Can someone explain the functionality of reportProgress in JavaScript, specifically when used with Angular Typescript? I am having trouble finding documentation on this. return this.httpClient.request<ProductResponse>('get',`${this.basePath ...

struggling to implement dynamic reactive forms with Angular

Currently, I am experimenting with building a dynamic reactive form using Angular. While I have successfully implemented the looping functionality, I am facing some challenges in displaying it the way I want. <form [formGroup]="registerForm" (ngSubmit) ...

Using multiple MaterialUI components in a JavaScript page with React can pose challenges

Incorporating multiple MaterialUI Cards in my project, I encountered an issue where all the cards would expand or the select values would change simultaneously. Despite using unique key values and mapped components with distinct keys, the problem persisted ...

Automating the process of rewirting git commit messages on a branch using Git

Is there a way to automate the rewriting of commit messages containing a specific substring on a particular branch? For example, in a repository like this: https://i.sstatic.net/3e4bW.png I want to modify all commit messages on the mybranch branch (not o ...

Angular 2 lacks compatibility with SVG

I have a website where I want to include SVG images inline with my HTML using Angular 2. However, when I try to load the SVG icons within a component, they do not display correctly. Instead, I see the following: https://i.sstatic.net/Ozo6E.png You can vi ...

In TypeScript, the NonNullable type is like Required, but it ensures that all object properties are converted to non-

When working with TypeScript, you may have come across the Required type which transforms object properties into defined ones. For instance: interface Person { name?: string; age?: number; } Using Required<Person> will result in: interface Pe ...

After compilation, any variables declared within a module remain undefined

I have declared the following files app.types.ts /// <reference path="../../typings/tsd.d.ts"/> module App{ export var Module = "website"; //---------------Controller Base Types--------------- export interface IScope extends ng.ISco ...

What is the process for extracting the elements of an array fetched from a service in Angular 2?

Currently, I am learning Angular 2 + PrimeNG and going through a quick start project available at the following link: https://github.com/primefaces/primeng-quickstart The project is a CRUD application and it functions flawlessly. The data is neatly displa ...

Difficulty in detecting variable modifications during testing - Angular2+

After successful login, I expect a certain variable to be updated with the appropriate value. However, during testing, all I see is 'undefined' returned. This variable does change when interacting with the app, showing an error message like &apo ...

Does Typescript not provide typecasting for webviews?

Typescript in my project does not recognize webviews. An example is: const webview = <webview> document.getElementById("foo"); An error is thrown saying "cannot find name 'webview'". How can I fix this issue? It works fine with just javas ...

Incorporate personalized No Data Available message in ngx-datatable

How can I customize the no data message for ngx-datatable? I want to avoid displaying the default message that comes with it. Here is what I have attempted so far: <div *ngIf="showTable"> <ngx-datatable [rows]="rows"> ...

Tab-based Ionic 2 advertising campaign featuring banners

Is there a way to incorporate an advertisement banner image above the tabs in ionic 2? Any suggestions on how I can achieve this or create the banner in that specific position? ...

What is the best way to merge the results of several runs of an observable function

When working with Firestore, I need to retrieve multiple documents, each with a unique sourceAddressValue. This means for a list of N strings, I may need to fetch N documents. I attempted the following approach: getLocationAddresses(addresses: string[]) { ...

I need help differentiating "namespace" from "static attributes" in TypeScript

Separating namespace from static properties in TypeScript can sometimes be tricky. error: 'ClassA' only refers to a type, but is being used as a namespace here. class ClassA { static ClassB = class { }; } type T = ClassA // ok type T = C ...

When working with Typescript and React, you may encounter an issue where an element implicitly has an 'any' type because the type 'State' has no index signature. This can lead to

In my current mini project, I am using Typescript and React. As someone new to Typescript, I am currently in the process of learning it. Within the project, I have a state defined as follows: type State = { field1: string, field2: string, field3: n ...

typescript create object with some properties using object literal

Is there a way to initialize an instance of a class with an object literal that doesn't contain all the elements in the class, but those present are part of the class? class Example{ text:string; number:number; displayResult(){return thi ...

The speed of the OpenLayers web application is significantly hindered when accessed from a mobile device using Android

Although it may seem like a common question that should be closed, I have reached a roadblock and cannot find a solution. I hope to provide enough details to make this question suitable for SO. I am currently working on an OpenLayers web application that ...