code: def per_file(f, args, video_process, model, writer):
      id, f = f
      f_name = f"{os.sep}".join(os.path.normpath(f).split(os.sep)[-3:])[
          :-4
      ]
      temp_aud_path = os.path.join(f"./data/temp/{args.gpu}", f_name)
      if not os.path.exists(os.path.dirname(temp_aud_path)):
          os.makedirs(os.path.dirname(temp_aud_path), exist_ok=True)
      if os.path.exists(
          os.path.join(args.landmark_path, f_name + ".pkl")
      ):
          with open(
              os.path.join(args.landmark_path, f_name + ".pkl"), "rb"
          ) as pkl_file:
              lm = pickle.load(pkl_file)
          vid_name = f
          vid = load_video(vid_name)
  
          if all(x is None for x in lm) or len(vid) == 0:
              return
  
          if len(vid) > 600:
              return
  
          output = video_process(vid, lm)
          if output is None:
              return
  
          os.system(
              f"ffmpeg -loglevel panic -nostdin -y -i {vid_name} \
                  -acodec pcm_s16le -ar 16000 -ac 1 {temp_aud_path}.wav"
          )
  
          video_feats, _, _ = output  # T, H, W
  
          sample_rate, wav_data = wavfile.read(f"{temp_aud_path}.wav")
          audio_feats = logfbank(
              wav_data, samplerate=sample_rate
          ).astype(
              np.float32
          )  # [T, F]
          # [T/stack_order_audio, F*stack_order_audio]
          audio_feats = stacker(audio_feats, 4)
          if audio_feats is not None and video_feats is not None:
              diff = len(audio_feats) - len(video_feats)
          if diff < 0:
              audio_feats = np.concatenate(
                  [
                      audio_feats,
                      np.zeros(
                          [-diff, audio_feats.shape[-1]],
                          dtype=audio_feats.dtype,
                      ),
                  ]
              )
          elif diff > 0:
              audio_feats = audio_feats[:-diff]
          audio_feats = torch.FloatTensor(audio_feats)
          with torch.no_grad():
              audio_feats = F.layer_norm(
                  audio_feats, audio_feats.shape[1:]
              )
          audio_feats = audio_feats.unsqueeze(0)
  
          # [B, T, H, W, C] -> [B, C, T, H, W]
          video_feats = (
              torch.FloatTensor(video_feats).unsqueeze(-1).unsqueeze(0)
          )  # B, T, H, W, C
          video_feats = video_feats.permute(0, 4, 1, 2, 3).contiguous()
          # [B, T, F] -> [B, F, T]
          audio_feats = audio_feats.transpose(1, 2).contiguous()
  
          xs = {
              "video": video_feats.cuda(),
              "audio": audio_feats.cuda(),
          }
          feats = model.forward_fusion(xs)
  
          writer[id] = (
              feats.squeeze(0)
              .transpose(0, 1)
              .contiguous()
              .cpu()
              .numpy()
          )
  
          os.system(f"rm {temp_aud_path}.wav")
      return
  
file_path: espnet/egs2/lrs3/avsr1/local/extract_av_feature.py
imports: import argparse
  import os
  import pickle
  import cv2
  import numpy
  import torch
  import torch.nn.functional
  from face_alignment import VideoProcess
  from python_speech_features import logfbank
  from scipy.io import wavfile
  from espnet2.asr.encoder.avhubert_encoder import FairseqAVHubertEncoder
  from espnet.utils.cli_writers import file_writer_helper
label_desc: Use image node_id 4 for calling a global function with example usage: per_file(f, args, video_process, model, writer) without return types