abema / go-mp4

Go library for reading and writing MP4 file
https://dev.to/sunfishshogi/go-mp4-golang-library-and-cli-tool-for-mp4-52o1
MIT License
468 stars 30 forks source link

Create new Atom. #117

Closed Sorrow446 closed 2 years ago

Sorrow446 commented 2 years ago
func copy(w *mp4.Writer, h *mp4.ReadHandle) error {
    _, err := w.StartBox(&h.BoxInfo)
    if err != nil {
        return err
    }
    box, _, err := h.ReadPayload()
    if err != nil {
        return err
    }
    _, err = mp4.Marshal(w, box, h.BoxInfo.Context)
    if err != nil {
        return err
    }
    _, err = h.Expand()
    if err != nil {
        return err
    }
    _, err = w.EndBox()
    return err
}

func main() {
    ctx := mp4.Context{
        UnderUdta:         true,
        UnderIlstMeta:     true,
        UnderIlst:         true,
        UnderIlstFreeMeta: true,
    }
    f, err := os.OpenFile("in.m4a", os.O_RDONLY, 0755)
    if err != nil {
        panic(err)
    }
        defer f.Close()
    outf, err := os.OpenFile("out.m4a", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0755)
    if err != nil {
        panic(err)
    }
    defer outf.Close()
    r := bufseekio.NewReadSeeker(f, 128*1024, 4)
    w := mp4.NewWriter(outf)
    _, err = mp4.ReadBoxStructure(r, func(h *mp4.ReadHandle) (interface{}, error) {
        fmt.Println(h.BoxInfo.Type)
        switch h.BoxInfo.Type {
        case mp4.BoxTypeMoov(), mp4.BoxTypeUdta(), mp4.BoxTypeMeta():
            err := copy(w, h)
            return nil, err
        case mp4.BoxTypeIlst():
            marshalData := func(val string) error {
                _, err = w.StartBox(&mp4.BoxInfo{Type: mp4.BoxTypeData(), Context: ctx})
                if err != nil {
                    return err
                }
                var boxData = &mp4.Data{
                    DataType: mp4.DataTypeStringUTF8,
                    Data:     []byte(val),
                }
                _, err = mp4.Marshal(w, boxData, ctx)
                if err != nil {
                    return err
                }
                _, err = w.EndBox()
                return err
            }
            addMeta := func(tag mp4.BoxType, val string) error {
                _, err = w.StartBox(&mp4.BoxInfo{Type: tag, Context: ctx})
                if err != nil {
                    return err
                }
                err = marshalData(val)
                if err != nil {
                    return err
                }
                _, err = w.EndBox()
                return err
            }
            err := copy(w, h)
            if err != nil {
                return nil, err
            }
            err = addMeta(mp4.BoxType{'\251', 'a', 'l', 'b'}, "test")
            if err != nil {
                return nil, err
            }
            //currentKey = "Album"
            return nil, nil
        default:
            return nil, w.CopyBox(r, &h.BoxInfo)
        }
    })
    if err != nil {
        panic(err)
    }
}
             Atom ilst @ 42910 of size: 383449, ends @ 426359
                 Atom trkn @ 42918 of size: 32, ends @ 42950
                     Atom data @ 42926 of size: 24, ends @ 42950
                 Atom aART @ 42950 of size: 30, ends @ 42980
                     Atom data @ 42958 of size: 22, ends @ 42980
                 Atom ©ART @ 42980 of size: 27, ends @ 43007
                     Atom data @ 42988 of size: 19, ends @ 43007
                 Atom ©wrt @ 43007 of size: 28, ends @ 43035
                     Atom data @ 43015 of size: 20, ends @ 43035
                 Atom ---- @ 43035 of size: 77, ends @ 43112
                     Atom mean @ 43043 of size: 28, ends @ 43071
                     Atom name @ 43071 of size: 24, ends @ 43095
                     Atom data @ 43095 of size: 17, ends @ 43112
                 Atom ©nam @ 43112 of size: 25, ends @ 43137
                     Atom data @ 43120 of size: 17, ends @ 43137
                 Atom ©too @ 43137 of size: 37, ends @ 43174
                     Atom data @ 43145 of size: 29, ends @ 43174
                 Atom covr @ 43174 of size: 383185, ends @ 426359
                     Atom data @ 43182 of size: 332356, ends @ 375538
                     Atom data @ 375538 of size: 50821, ends @ 426359
             Atom ©alb @ 426359 of size: 28, ends @ 426387

Hello. I'm trying to write a new ©alb atom inside ilst, but it writes it outside of it instead. Could you give me a working example?

sunfish-shogi commented 2 years ago

@Sorrow446 The box size header of ilst will be fixed by w.EndBox in copy.

In this code, addMeta function will be called after w.EndBox which called by copy. Therefore ©alb will be appended as brother of ilst box.

If you want to append it as child of ilst , you should call addMeta between mp4.Marshal and w.EndBox of ilst box.

For example,

w.StartBox(infoA)
mp4.Marshal(w, a, ctx)

w.StartBox(infoB)
mp4.Marshal(w, b, ctx)
w.EndBox() // end of B

w.StartBox(infoC)
mp4.Marshal(w, c, ctx)
w.EndBox() // end of C

w.EndBox(...) // end of A

w.StartBox(infoD)
mp4.Marshal(w, d, ctx)
w.EndBox() // end of D

will generates following tree:

Sorrow446 commented 2 years ago

Working great now. I'm still getting used to your library. Thanks for the quick reply and your great library.